<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="flex-flow" sub_properties="flex-direction flex-wrap" extra_prefixes="webkit"
                    spec="https://drafts.csswg.org/css-flexbox/#flex-flow-property">
    use properties::longhands::{flex_direction, flex_wrap};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut direction = None;
        let mut wrap = None;
        loop {
            if direction.is_none() {
                if let Ok(value) = input.try(|input| flex_direction::parse(context, input)) {
                    direction = Some(value);
                    continue
                }
            }
            if wrap.is_none() {
                if let Ok(value) = input.try(|input| flex_wrap::parse(context, input)) {
                    wrap = Some(value);
                    continue
                }
            }
            break
        }

        if direction.is_none() && wrap.is_none() {
            return Err(())
        }
        Ok(Longhands {
            flex_direction: unwrap_or_initial!(flex_direction, direction),
            flex_wrap: unwrap_or_initial!(flex_wrap, wrap),
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            self.flex_direction.to_css(dest)?;
            dest.write_str(" ")?;
            self.flex_wrap.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="flex" sub_properties="flex-grow flex-shrink flex-basis" extra_prefixes="webkit"
                    spec="https://drafts.csswg.org/css-flexbox/#flex-property">
    use values::specified::Number;

    fn parse_flexibility(context: &ParserContext, input: &mut Parser)
                         -> Result<(Number, Option<Number>),()> {
        let grow = try!(Number::parse_non_negative(context, input));
        let shrink = input.try(|i| Number::parse_non_negative(context, i)).ok();
        Ok((grow, shrink))
    }

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut grow = None;
        let mut shrink = None;
        let mut basis = None;

        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(Longhands {
                flex_grow: Number::new(0.0),
                flex_shrink: Number::new(0.0),
                flex_basis: longhands::flex_basis::SpecifiedValue::auto(),
            })
        }
        loop {
            if grow.is_none() {
                if let Ok((flex_grow, flex_shrink)) = input.try(|i| parse_flexibility(context, i)) {
                    grow = Some(flex_grow);
                    shrink = flex_shrink;
                    continue
                }
            }
            if basis.is_none() {
                if let Ok(value) = input.try(|input| longhands::flex_basis::parse(context, input)) {
                    basis = Some(value);
                    continue
                }
            }
            break
        }

        if grow.is_none() && basis.is_none() {
            return Err(())
        }
        Ok(Longhands {
            flex_grow: grow.unwrap_or(Number::new(1.0)),
            flex_shrink: shrink.unwrap_or(Number::new(1.0)),
            flex_basis: basis.unwrap_or(longhands::flex_basis::SpecifiedValue::zero()),
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.flex_grow.to_css(dest));
            try!(dest.write_str(" "));

            try!(self.flex_shrink.to_css(dest));
            try!(dest.write_str(" "));

            self.flex_basis.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="grid-gap" sub_properties="grid-row-gap grid-column-gap"
                    spec="https://drafts.csswg.org/css-grid/#propdef-grid-gap"
                    products="gecko">
  use properties::longhands::{grid_row_gap, grid_column_gap};

  pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
      let row_gap = grid_row_gap::parse(context, input)?;
      let column_gap = input.try(|input| grid_column_gap::parse(context, input)).unwrap_or(row_gap.clone());

      Ok(Longhands {
        grid_row_gap: row_gap,
        grid_column_gap: column_gap,
      })
  }

  impl<'a> ToCss for LonghandsToSerialize<'a>  {
      fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
          if self.grid_row_gap == self.grid_column_gap {
            self.grid_row_gap.to_css(dest)
          } else {
            self.grid_row_gap.to_css(dest)?;
            dest.write_str(" ")?;
            self.grid_column_gap.to_css(dest)
          }
      }
  }

</%helpers:shorthand>
<commit_msg>Auto merge of #16322 - tamamu:place-shorthand, r=upsuper<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<%helpers:shorthand name="flex-flow" sub_properties="flex-direction flex-wrap" extra_prefixes="webkit"
                    spec="https://drafts.csswg.org/css-flexbox/#flex-flow-property">
    use properties::longhands::{flex_direction, flex_wrap};

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut direction = None;
        let mut wrap = None;
        loop {
            if direction.is_none() {
                if let Ok(value) = input.try(|input| flex_direction::parse(context, input)) {
                    direction = Some(value);
                    continue
                }
            }
            if wrap.is_none() {
                if let Ok(value) = input.try(|input| flex_wrap::parse(context, input)) {
                    wrap = Some(value);
                    continue
                }
            }
            break
        }

        if direction.is_none() && wrap.is_none() {
            return Err(())
        }
        Ok(Longhands {
            flex_direction: unwrap_or_initial!(flex_direction, direction),
            flex_wrap: unwrap_or_initial!(flex_wrap, wrap),
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            self.flex_direction.to_css(dest)?;
            dest.write_str(" ")?;
            self.flex_wrap.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="flex" sub_properties="flex-grow flex-shrink flex-basis" extra_prefixes="webkit"
                    spec="https://drafts.csswg.org/css-flexbox/#flex-property">
    use values::specified::Number;

    fn parse_flexibility(context: &ParserContext, input: &mut Parser)
                         -> Result<(Number, Option<Number>),()> {
        let grow = try!(Number::parse_non_negative(context, input));
        let shrink = input.try(|i| Number::parse_non_negative(context, i)).ok();
        Ok((grow, shrink))
    }

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let mut grow = None;
        let mut shrink = None;
        let mut basis = None;

        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(Longhands {
                flex_grow: Number::new(0.0),
                flex_shrink: Number::new(0.0),
                flex_basis: longhands::flex_basis::SpecifiedValue::auto(),
            })
        }
        loop {
            if grow.is_none() {
                if let Ok((flex_grow, flex_shrink)) = input.try(|i| parse_flexibility(context, i)) {
                    grow = Some(flex_grow);
                    shrink = flex_shrink;
                    continue
                }
            }
            if basis.is_none() {
                if let Ok(value) = input.try(|input| longhands::flex_basis::parse(context, input)) {
                    basis = Some(value);
                    continue
                }
            }
            break
        }

        if grow.is_none() && basis.is_none() {
            return Err(())
        }
        Ok(Longhands {
            flex_grow: grow.unwrap_or(Number::new(1.0)),
            flex_shrink: shrink.unwrap_or(Number::new(1.0)),
            flex_basis: basis.unwrap_or(longhands::flex_basis::SpecifiedValue::zero()),
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a>  {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            try!(self.flex_grow.to_css(dest));
            try!(dest.write_str(" "));

            try!(self.flex_shrink.to_css(dest));
            try!(dest.write_str(" "));

            self.flex_basis.to_css(dest)
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="grid-gap" sub_properties="grid-row-gap grid-column-gap"
                    spec="https://drafts.csswg.org/css-grid/#propdef-grid-gap"
                    products="gecko">
  use properties::longhands::{grid_row_gap, grid_column_gap};

  pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
      let row_gap = grid_row_gap::parse(context, input)?;
      let column_gap = input.try(|input| grid_column_gap::parse(context, input)).unwrap_or(row_gap.clone());

      Ok(Longhands {
        grid_row_gap: row_gap,
        grid_column_gap: column_gap,
      })
  }

  impl<'a> ToCss for LonghandsToSerialize<'a>  {
      fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
          if self.grid_row_gap == self.grid_column_gap {
            self.grid_row_gap.to_css(dest)
          } else {
            self.grid_row_gap.to_css(dest)?;
            dest.write_str(" ")?;
            self.grid_column_gap.to_css(dest)
          }
      }
  }

</%helpers:shorthand>

<%helpers:shorthand name="place-content" sub_properties="align-content justify-content"
                    spec="https://drafts.csswg.org/css-align/#propdef-place-content"
                    products="gecko" disable_when_testing="True">
    use properties::longhands::align_content;
    use properties::longhands::justify_content;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let align = align_content::parse(context, input)?;
        let justify = input.try(|input| justify_content::parse(context, input))
                           .unwrap_or(justify_content::SpecifiedValue::from(align));

        Ok(Longhands {
            align_content: align,
            justify_content: justify,
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a> {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.align_content == self.justify_content {
                self.align_content.to_css(dest)
            } else {
                self.justify_content.to_css(dest)?;
                dest.write_str(" ")?;
                self.justify_content.to_css(dest)
            }
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="place-self" sub_properties="align-self justify-self"
                    spec="https://drafts.csswg.org/css-align/#place-self-property"
                    products="gecko" disable_when_testing="True">
    use values::specified::align::AlignJustifySelf;
    use parser::Parse;

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let align = AlignJustifySelf::parse(context, input)?;
        let justify = input.try(|input| AlignJustifySelf::parse(context, input)).unwrap_or(align.clone());

        Ok(Longhands {
            align_self: align,
            justify_self: justify,
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a> {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.align_self == self.justify_self {
                self.align_self.to_css(dest)
            } else {
                self.align_self.to_css(dest)?;
                dest.write_str(" ")?;
                self.justify_self.to_css(dest)
            }
        }
    }
</%helpers:shorthand>

<%helpers:shorthand name="place-items" sub_properties="align-items justify-items"
                    spec="https://drafts.csswg.org/css-align/#place-items-property"
                    products="gecko" disable_when_testing="True">
    use values::specified::align::{AlignItems, JustifyItems};
    use parser::Parse;

    impl From<AlignItems> for JustifyItems {
        fn from(align: AlignItems) -> JustifyItems {
            JustifyItems(align.0)
        }
    }

    pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
        let align = AlignItems::parse(context, input)?;
        let justify = input.try(|input| JustifyItems::parse(context, input))
                           .unwrap_or(JustifyItems::from(align));

        Ok(Longhands {
            align_items: align,
            justify_items: justify,
        })
    }

    impl<'a> ToCss for LonghandsToSerialize<'a> {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if self.align_items.0 == self.justify_items.0 {
                self.align_items.to_css(dest)
            } else {
                self.align_items.to_css(dest)?;
                dest.write_str(" ")?;
                self.justify_items.to_css(dest)
            }
        }
    }
</%helpers:shorthand>
<|endoftext|>


<commit_before>extern crate libc;

use self::libc::{c_int, size_t};
use std::io::{self, Read};

use byteorder::{BigEndian, ByteOrder};
use error::{Result, Error};

extern {
    fn snappy_compress(input: *const u8,
                       input_length: size_t,
                       compressed: *mut u8,
                       compressed_length: *mut size_t) -> c_int;

    fn snappy_max_compressed_length(source_length: size_t) -> size_t;

    fn snappy_uncompress(compressed: *const u8,
                             compressed_length: size_t,
                             uncompressed: *mut u8,
                             uncompressed_length: *mut size_t) -> c_int;

    fn snappy_uncompressed_length(compressed: *const u8,
                                  compressed_length: size_t,
                                  result: *mut size_t) -> c_int;
}

// ~ Uncompresse 'src' into 'dst'.
// ~ 'dst' will first be cleared and then populated with the uncompressed data.
// ~ No guarantees are provided about the contents of 'dst' if this function
// results in an error.
fn uncompress_into(src: &[u8], dst: &mut Vec<u8>) -> Result<()> {
    unsafe {
        let src_len = src.len() as size_t;
        let src_ptr = src.as_ptr();

        let mut dst_len: size_t = 0;
        snappy_uncompressed_length(src_ptr, src_len, &mut dst_len);

        // this is actually safe: we're merely clearing the vector
        // without the Drop implementation for the u8's executed
        dst.set_len(0);
        // now make sure the vector is large enough
        dst.reserve(dst_len as usize);
        let dst_ptr = dst.as_mut_ptr();
        if snappy_uncompress(src_ptr, src_len, dst_ptr, &mut dst_len) == 0 {
            dst.set_len(dst_len as usize);
            Ok(())
        } else {
            Err(Error::InvalidInputSnappy) // SNAPPY_INVALID_INPUT
        }
    }
}

pub fn compress(src: &[u8]) -> Result<Vec<u8>> {
    unsafe {
        let (_, x) = src.split_at(0);
        let srclen = x.len() as size_t;
        let psrc = x.as_ptr();
        let mut dstlen = snappy_max_compressed_length(srclen);
        let mut dst = Vec::with_capacity(dstlen as usize);
        let pdst = dst.as_mut_ptr();
        if snappy_compress(psrc, srclen, pdst, &mut dstlen) == 0 {
            dst.set_len(dstlen as usize);
            Ok(dst)
        } else {
            Err(Error::InvalidInputSnappy)
        }
    }
}

// --------------------------------------------------------------------

const MAGIC: &'static [u8] = &[0x82, b'S', b'N', b'A', b'P', b'P', b'Y', 0];

// ~ reads a i32 valud and "advances" the given slice by four bytes;
// assumes "slice" is a mutable reference to a &[u8].
macro_rules! next_i32 {
    ($slice:expr) => {{
        if $slice.len() < 4 {
            return Err(Error::UnexpectedEOF);
        }
        { let n = BigEndian::read_i32($slice);
          $slice = &$slice[4..];
          n
        }
    }}
}

/// Validates the expected header at the beginning of the
/// stream. Further, checks the version and compatibility of the
/// stream indicating we can parse the stream. Returns the rest of the
/// stream following the validated header.
fn validate_stream(mut stream: &[u8]) -> Result<&[u8]> {
    // ~ check the "header magic"
    if stream.len() < MAGIC.len() { return Err(Error::UnexpectedEOF); }
    if &stream[..MAGIC.len()] != MAGIC { return Err(Error::InvalidInputSnappy); }
    stream = &stream[MAGIC.len()..];
    // ~ let's be assertive and (for the moment) restrict ourselves to
    // version == 1 and compatibility == 1.
    let version = next_i32!(stream);
    if version != 1 { return Err(Error::InvalidInputSnappy); }
    let compat = next_i32!(stream);
    if compat != 1 { return Err(Error::InvalidInputSnappy); }
    Ok(stream)
}

#[test]
fn test_validate_stream() {
    let header = [0x82, 0x53, 0x4e, 0x41, 0x50, 0x50, 0x59, 0x00, 0, 0, 0, 1, 0, 0, 0, 1, 0x56];
    // ~ this must not result in a panic
    let rest = validate_stream(&header).unwrap();
    // ~ the rest of the input after the parsed header must be
    // correctly delivered
    assert_eq!(rest, &[0x56]);
}

// ~ An implementation of a reader over a stream of snappy compressed
// chunks as produced by org.xerial.snappy.SnappyOutputStream
// (https://github.com/xerial/snappy-java/ version: 1.1.1.*)
pub struct SnappyReader<'a> {
    // the compressed data itself
    compressed_data: &'a [u8],

    // a pointer into `uncompressed_chunk` indicating the next data
    // byte to serve
    uncompressed_pos: usize,
    // the uncompressed chunk of data available for consumption
    uncompressed_chunk: Vec<u8>,
}

impl<'a> SnappyReader<'a> {
    pub fn new(mut stream: &[u8]) -> Result<SnappyReader> {
        stream = try!(validate_stream(stream));
        Ok(SnappyReader {
            compressed_data: stream,
            uncompressed_pos: 0,
            uncompressed_chunk: Vec::new(),
        })
    }

    fn _read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if self.uncompressed_pos < self.uncompressed_chunk.len() {
            self.read_uncompressed(buf)
        } else if try!(self.next_chunk()) {
            self.read_uncompressed(buf)
        } else {
            Ok(0)
        }
    }

    fn read_uncompressed(&mut self, buf: &mut [u8]) -> Result<usize> {
        let n = try!((&self.uncompressed_chunk[self.uncompressed_pos..]).read(buf));
        self.uncompressed_pos += n;
        Ok(n)
    }

    fn next_chunk(&mut self) -> Result<bool> {
        if self.compressed_data.is_empty() {
            return Ok(false);
        }
        self.uncompressed_pos = 0;
        let chunk_size = next_i32!(self.compressed_data);
        if chunk_size <= 0 {
            return Err(Error::InvalidInputSnappy);
        }
        let chunk_size = chunk_size as usize;
        try!(uncompress_into(&self.compressed_data[..chunk_size], &mut self.uncompressed_chunk));
        self.compressed_data = &self.compressed_data[chunk_size..];
        Ok(true)
    }
}

impl<'a> Read for SnappyReader<'a> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self._read(buf) {
            Ok(n) => Ok(n),
            // ~ pass io errors through directly
            Err(Error::Io(io_error)) => Err(io_error),
            // ~ wrapp our other errors
            Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
        }
    }
}

// --------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use std::io::Read;

    use error::{Error, Result};
    use super::{compress, uncompress_into, SnappyReader};

    fn uncompress(src: &[u8]) -> Result<Vec<u8>> {
        let mut v = Vec::new();
        match uncompress_into(src, &mut v) {
            Ok(_) => Ok(v),
            Err(e) => Err(e),
        }
    }

    #[test]
    fn test_compress() {
        let msg = "This is test".as_bytes();
        let compressed = compress(msg).unwrap();
        let expected = &[12, 44, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116];
        assert_eq!(&compressed, expected);
    }

    #[test]
    fn test_uncompress() {
        // The vector should uncompress to "This is test"
        let compressed = &[12, 44, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116];
        let uncompressed = String::from_utf8(uncompress(compressed).unwrap()).unwrap();
        assert_eq!(&uncompressed, "This is test");
    }

    #[test]
    fn test_uncompress_invalid_input() {
        // The vector is an invalid snappy message (second byte modified on purpose)
        let compressed = &[12, 42, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116];
        let uncompressed = uncompress(compressed);
        assert!(uncompressed.is_err());
        assert!(if let Some(Error::InvalidInputSnappy) = uncompressed.err() { true } else { false });
    }

    #[test]
    fn test_snappy_reader() {
        static ORIGINAL: &'static str =
            include_str!("../../test-data/fetch1.txt");
        static COMPRESSED: &'static [u8] =
            include_bytes!("../../test-data/fetch1.snappy.chunked.4k");

        let mut buf = Vec::new();
        let mut r = SnappyReader::new(COMPRESSED).unwrap();
        r.read_to_end(&mut buf).unwrap();
        assert_eq!(ORIGINAL.as_bytes(), &buf[..]);
    }
}
<commit_msg>#! Improve performance when reading_to_end snappy compressed messages<commit_after>extern crate libc;

use self::libc::{c_int, size_t};
use std::io::{self, Read};

use byteorder::{BigEndian, ByteOrder};
use error::{Result, Error};

extern {
    fn snappy_compress(input: *const u8,
                       input_length: size_t,
                       compressed: *mut u8,
                       compressed_length: *mut size_t) -> c_int;

    fn snappy_max_compressed_length(source_length: size_t) -> size_t;

    fn snappy_uncompress(compressed: *const u8,
                             compressed_length: size_t,
                             uncompressed: *mut u8,
                             uncompressed_length: *mut size_t) -> c_int;

    fn snappy_uncompressed_length(compressed: *const u8,
                                  compressed_length: size_t,
                                  result: *mut size_t) -> c_int;
}

// ~ Uncompresse 'src' into 'dst'.
// ~ 'dst' will receive the newly uncompressed data appended.
// ~ No guarantees are provided about the contents of 'dst' if this function
// results in an error.
fn uncompress_into(src: &[u8], dst: &mut Vec<u8>) -> Result<()> {
    unsafe {
        let src_len = src.len() as size_t;
        let src_ptr = src.as_ptr();

        let dst_cur_len = dst.len();
        let mut dst_add_len: size_t = 0;
        snappy_uncompressed_length(src_ptr, src_len, &mut dst_add_len);

        // now make sure the vector is large enough
        dst.reserve(dst_add_len as usize);
        let dst_ptr = dst[dst_cur_len..].as_mut_ptr();
        if snappy_uncompress(src_ptr, src_len, dst_ptr, &mut dst_add_len) == 0 {
            dst.set_len(dst_cur_len + dst_add_len as usize);
            Ok(())
        } else {
            Err(Error::InvalidInputSnappy) // SNAPPY_INVALID_INPUT
        }
    }
}

pub fn compress(src: &[u8]) -> Result<Vec<u8>> {
    unsafe {
        let (_, x) = src.split_at(0);
        let srclen = x.len() as size_t;
        let psrc = x.as_ptr();
        let mut dstlen = snappy_max_compressed_length(srclen);
        let mut dst = Vec::with_capacity(dstlen as usize);
        let pdst = dst.as_mut_ptr();
        if snappy_compress(psrc, srclen, pdst, &mut dstlen) == 0 {
            dst.set_len(dstlen as usize);
            Ok(dst)
        } else {
            Err(Error::InvalidInputSnappy)
        }
    }
}

// --------------------------------------------------------------------

const MAGIC: &'static [u8] = &[0x82, b'S', b'N', b'A', b'P', b'P', b'Y', 0];

// ~ reads a i32 valud and "advances" the given slice by four bytes;
// assumes "slice" is a mutable reference to a &[u8].
macro_rules! next_i32 {
    ($slice:expr) => {{
        if $slice.len() < 4 {
            return Err(Error::UnexpectedEOF);
        }
        { let n = BigEndian::read_i32($slice);
          $slice = &$slice[4..];
          n
        }
    }}
}

/// Validates the expected header at the beginning of the
/// stream. Further, checks the version and compatibility of the
/// stream indicating we can parse the stream. Returns the rest of the
/// stream following the validated header.
fn validate_stream(mut stream: &[u8]) -> Result<&[u8]> {
    // ~ check the "header magic"
    if stream.len() < MAGIC.len() { return Err(Error::UnexpectedEOF); }
    if &stream[..MAGIC.len()] != MAGIC { return Err(Error::InvalidInputSnappy); }
    stream = &stream[MAGIC.len()..];
    // ~ let's be assertive and (for the moment) restrict ourselves to
    // version == 1 and compatibility == 1.
    let version = next_i32!(stream);
    if version != 1 { return Err(Error::InvalidInputSnappy); }
    let compat = next_i32!(stream);
    if compat != 1 { return Err(Error::InvalidInputSnappy); }
    Ok(stream)
}

#[test]
fn test_validate_stream() {
    let header = [0x82, 0x53, 0x4e, 0x41, 0x50, 0x50, 0x59, 0x00, 0, 0, 0, 1, 0, 0, 0, 1, 0x56];
    // ~ this must not result in a panic
    let rest = validate_stream(&header).unwrap();
    // ~ the rest of the input after the parsed header must be
    // correctly delivered
    assert_eq!(rest, &[0x56]);
}

// ~ An implementation of a reader over a stream of snappy compressed
// chunks as produced by org.xerial.snappy.SnappyOutputStream
// (https://github.com/xerial/snappy-java/ version: 1.1.1.*)
pub struct SnappyReader<'a> {
    // the compressed data itself
    compressed_data: &'a [u8],

    // a pointer into `uncompressed_chunk` indicating the next data
    // byte to serve
    uncompressed_pos: usize,
    // the uncompressed chunk of data available for consumption
    uncompressed_chunk: Vec<u8>,
}

impl<'a> SnappyReader<'a> {
    pub fn new(mut stream: &[u8]) -> Result<SnappyReader> {
        stream = try!(validate_stream(stream));
        Ok(SnappyReader {
            compressed_data: stream,
            uncompressed_pos: 0,
            uncompressed_chunk: Vec::new(),
        })
    }

    fn _read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if self.uncompressed_pos < self.uncompressed_chunk.len() {
            self.read_uncompressed(buf)
        } else if try!(self.next_chunk()) {
            self.read_uncompressed(buf)
        } else {
            Ok(0)
        }
    }

    fn read_uncompressed(&mut self, buf: &mut [u8]) -> Result<usize> {
        let n = try!((&self.uncompressed_chunk[self.uncompressed_pos..]).read(buf));
        self.uncompressed_pos += n;
        Ok(n)
    }

    fn next_chunk(&mut self) -> Result<bool> {
        if self.compressed_data.is_empty() {
            return Ok(false);
        }
        self.uncompressed_pos = 0;
        let chunk_size = next_i32!(self.compressed_data);
        if chunk_size <= 0 {
            return Err(Error::InvalidInputSnappy);
        }
        let chunk_size = chunk_size as usize;
        self.uncompressed_chunk.clear();
        try!(uncompress_into(&self.compressed_data[..chunk_size], &mut self.uncompressed_chunk));
        self.compressed_data = &self.compressed_data[chunk_size..];
        Ok(true)
    }

    fn _read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
        let init_len = buf.len();
        // ~ first consume already uncompressed and unconsumed data - if any
        if self.uncompressed_pos < self.uncompressed_chunk.len() {
            let rest = &self.uncompressed_chunk[self.uncompressed_pos..];
            buf.extend(rest);
            self.uncompressed_pos += rest.len();
        }
        // ~ now decompress data directly to the output target
        while !self.compressed_data.is_empty() {
            let chunk_size = next_i32!(self.compressed_data);
            if chunk_size <= 0 {
                return Err(Error::InvalidInputSnappy);
            }
            let (c1, c2) = self.compressed_data.split_at(chunk_size as usize);
            try!(uncompress_into(c1, buf));
            self.compressed_data = c2;
        }
        Ok(buf.len() - init_len)
    }
}

macro_rules! to_io_error {
    ($expr:expr) => {
        match $expr {
            Ok(n) => Ok(n),
            // ~ pass io errors through directly
            Err(Error::Io(io_error)) => Err(io_error),
            // ~ wrapp our other errors
            Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
        }
    }
}

impl<'a> Read for SnappyReader<'a> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        to_io_error!(self._read(buf))
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        to_io_error!(self._read_to_end(buf))
    }
}

// --------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use std::io::Read;

    use error::{Error, Result};
    use super::{compress, uncompress_into, SnappyReader};

    fn uncompress(src: &[u8]) -> Result<Vec<u8>> {
        let mut v = Vec::new();
        match uncompress_into(src, &mut v) {
            Ok(_) => Ok(v),
            Err(e) => Err(e),
        }
    }

    #[test]
    fn test_compress() {
        let msg = "This is test".as_bytes();
        let compressed = compress(msg).unwrap();
        let expected = &[12, 44, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116];
        assert_eq!(&compressed, expected);
    }

    #[test]
    fn test_uncompress() {
        // The vector should uncompress to "This is test"
        let compressed = &[12, 44, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116];
        let uncompressed = String::from_utf8(uncompress(compressed).unwrap()).unwrap();
        assert_eq!(&uncompressed, "This is test");
    }

    #[test]
    fn test_uncompress_invalid_input() {
        // The vector is an invalid snappy message (second byte modified on purpose)
        let compressed = &[12, 42, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116];
        let uncompressed = uncompress(compressed);
        assert!(uncompressed.is_err());
        assert!(if let Some(Error::InvalidInputSnappy) = uncompressed.err() { true } else { false });
    }

    static ORIGINAL: &'static str =
        include_str!("../../test-data/fetch1.txt");
    static COMPRESSED: &'static [u8] =
        include_bytes!("../../test-data/fetch1.snappy.chunked.4k");

    #[test]
    fn test_snappy_reader_read() {
        let mut buf = Vec::new();
        let mut r = SnappyReader::new(COMPRESSED).unwrap();

        let mut tmp_buf = [0u8; 1024];
        loop {
            match r.read(&mut tmp_buf).unwrap() {
                0 => break,
                n => buf.extend(&tmp_buf[..n]),
            }
        }
        assert_eq!(ORIGINAL.as_bytes(), &buf[..]);
    }

    #[test]
    fn test_snappy_reader_read_to_end() {
        let mut buf = Vec::new();
        let mut r = SnappyReader::new(COMPRESSED).unwrap();
        r.read_to_end(&mut buf).unwrap();
        assert_eq!(ORIGINAL.as_bytes(), &buf[..]);
    }
}
<|endoftext|>


<commit_before>extern mod std;
use std::net::tcp;
use std::net::ip;
use std::uv;
use std::arc::RWARC;
use core::hashmap::linear::LinearMap; // core::hashmap::HashMap in 0.7

fn main() {
    io::println("Started");
    let iotask = &uv::global_loop::get();
    let port = 6380;

    let mut data = ~LinearMap::new::<~[u8], ~[u8]>();
    let dataARC = RWARC(data);

    let listen_res = do tcp::listen(ip::v4::parse_addr("127.0.0.1"), port, 1000, iotask,
        |_kill_ch| {
            // pass the kill_ch to your main loop or wherever you want
            // to be able to externally kill the server from
            io::println(fmt!("Server is listening on port %u", port));
        }
    ) |new_conn, kill_ch| {
        io::println("New client");

        let (port, channel) = comm::stream::<option::Option<tcp::TcpErrData>>();
        let localARC = dataARC.clone();

        do task::spawn_supervised {
            let accept_result = tcp::accept(new_conn);
            match accept_result {
                Err(accept_error) => {
                    io::stderr().write_line("Failed to accept connection");
                    channel.send(Some(accept_error));
                },
                Ok(sock) => {
                    let peer_addr = &sock.get_peer_addr();
                    io::println(fmt!("Client connected: %s on port %u", ip::format_addr(peer_addr), ip::get_port(peer_addr)));
                    channel.send(None);

                    let sockbuf = tcp::socket_buf(sock);
                    loop {
                        let parse_res = parse_args(sockbuf);
                        match parse_res {
                            Err(msg) => {
                                sockbuf.write_str(msg);
                            },
                            Ok(args) => {
                                let response = cmd_dispatcher(localARC.clone(), args);
                                sockbuf.write(response);
                            }
                        }
                    }
                }
            }
        };

        match port.recv() {
          // shut down listen()
          Some(err_data) => kill_ch.send(Some(err_data)),
          // wait for next connection
          None => ()
        }
    };

    if listen_res.is_err() {
        io::stderr().write_line(fmt!("Failed to bind address: %?", listen_res.get_err()));
    }
}

fn parse_args(buf: tcp::TcpSocketBuf) -> Result<~[~[u8]], ~str> {
    let first_char = buf.read_char();
    let has_arg_count = first_char == '*';
    let mut args = ~[];

    if has_arg_count {
        let mut arg_count;
        match uint::from_str(buf.read_until('\r', false)) {
            Some(count) => {
                arg_count = count;
            },
            None => {
                return Err(~"Could not parse argument count as uint");
            }
        }

        // discard \n
        buf.read_byte();

        while arg_count > 0 {
            let chr = buf.read_char();
            let has_arg_len = chr == '$';
            if !has_arg_len {
                return Err(fmt!("No argument length found, expected $n, got %?", chr));
            }
            let arg_len;
            match uint::from_str(buf.read_until('\r', false)) {
                Some(count) => {
                    arg_len = count;
                },
                None => {
                    return Err(~"Could not parse argument length as uint");
                }
            }
            // discard \n
            buf.read_byte();

            args.push(buf.read_bytes(arg_len));
            arg_count -= 1;

            // discard \r\n
            buf.read_bytes(2);
        }
    } else {
        let input = str::append(str::from_char(first_char), buf.read_until('\r', false));
        // discard \n
        buf.read_char();

        for str::each_split_char_nonempty(input, ' ') |word| {
            args.push(word.to_bytes());
        }
    }

    Ok(args)
}

fn cmd_dispatcher(arc: RWARC<~LinearMap<~[u8], ~[u8]>>, args: ~[~[u8]]) -> ~[u8] {
    let command = str::from_bytes(args[0]).to_lower();

    //io::println(fmt!("%s: %?", command, args));

    let mut output = ~[];
    if command == ~"get" {
        do arc.read() |data| {
            let res = data.find(&args[1]);
            if res.is_some() {
                output = str::concat(~[~"$", res.unwrap().len().to_str(), ~"\r\n"]).to_bytes();
                vec::push_all(&mut output, *res.unwrap());
                vec::push_all(&mut output, "\r\n".to_bytes());
            } else {
                output = "$-1\r\n".to_bytes();
            }
        }
    } else if command == ~"set" {
        do arc.write() |data| {
            data.insert(copy args[1], copy args[2]);

            output = "+OK\r\n".to_bytes();
        }
    } else {
        output = fmt!("-ERR unknown command '%s'\r\n", command).to_bytes();
    }

    output
}
<commit_msg>Remove some unnecessary copies/clone<commit_after>extern mod std;
use std::net::tcp;
use std::net::ip;
use std::uv;
use std::arc::RWARC;
use core::hashmap::linear::LinearMap; // core::hashmap::HashMap in 0.7

fn main() {
    io::println("Started");
    let iotask = &uv::global_loop::get();
    let port = 6380;

    let mut data = ~LinearMap::new::<~[u8], ~[u8]>();
    let dataARC = RWARC(data);

    let listen_res = do tcp::listen(ip::v4::parse_addr("127.0.0.1"), port, 1000, iotask,
        |_kill_ch| {
            // pass the kill_ch to your main loop or wherever you want
            // to be able to externally kill the server from
            io::println(fmt!("Server is listening on port %u", port));
        }
    ) |new_conn, kill_ch| {
        io::println("New client");

        let (port, channel) = comm::stream::<Option<tcp::TcpErrData>>();
        let localARC = dataARC.clone();

        do task::spawn_supervised {
            let accept_result = tcp::accept(new_conn);
            match accept_result {
                Err(accept_error) => {
                    io::stderr().write_line("Failed to accept connection");
                    channel.send(Some(accept_error));
                },
                Ok(sock) => {
                    let peer_addr = &sock.get_peer_addr();
                    io::println(fmt!("Client connected: %s on port %u", ip::format_addr(peer_addr), ip::get_port(peer_addr)));
                    channel.send(None);

                    let sockbuf = tcp::socket_buf(sock);
                    loop {
                        let parse_res = parse_args(sockbuf);
                        match parse_res {
                            Err(msg) => {
                                sockbuf.write_str(msg);
                            },
                            Ok(args) => {
                                let response = cmd_dispatcher(&localARC, args);
                                sockbuf.write(response);
                            }
                        }
                    }
                }
            }
        };

        match port.recv() {
          // shut down listen()
          Some(err_data) => kill_ch.send(Some(err_data)),
          // wait for next connection
          None => ()
        }
    };

    if listen_res.is_err() {
        io::stderr().write_line(fmt!("Failed to bind address: %?", listen_res.get_err()));
    }
}

fn parse_args(buf: tcp::TcpSocketBuf) -> Result<~[~[u8]], ~str> {
    let first_char = buf.read_char();
    let has_arg_count = first_char == '*';
    let mut args = ~[];

    if has_arg_count {
        let mut arg_count;
        match uint::from_str(buf.read_until('\r', false)) {
            Some(count) => {
                arg_count = count;
            },
            None => {
                return Err(~"Could not parse argument count as uint");
            }
        }

        // discard \n
        buf.read_byte();

        while arg_count > 0 {
            let chr = buf.read_char();
            let has_arg_len = chr == '$';
            if !has_arg_len {
                return Err(fmt!("No argument length found, expected $n, got %?", chr));
            }
            let arg_len;
            match uint::from_str(buf.read_until('\r', false)) {
                Some(count) => {
                    arg_len = count;
                },
                None => {
                    return Err(~"Could not parse argument length as uint");
                }
            }
            // discard \n
            buf.read_byte();

            args.push(buf.read_bytes(arg_len));
            arg_count -= 1;

            // discard \r\n
            buf.read_bytes(2);
        }
    } else {
        let input = str::append(str::from_char(first_char), buf.read_until('\r', false));
        // discard \n
        buf.read_char();

        for str::each_split_char_nonempty(input, ' ') |word| {
            args.push(word.to_bytes());
        }
    }

    Ok(args)
}

fn cmd_dispatcher(arc: &RWARC<~LinearMap<~[u8], ~[u8]>>, mut args: ~[~[u8]]) -> ~[u8] {
    let command = str::from_bytes(args[0]).to_lower();

    //io::println(fmt!("%s: %?", command, args));

    let mut output = ~[];
    if command == ~"get" {
        do arc.read() |data| {
            let res = data.find(&args[1]);
            if res.is_some() {
                output = str::concat(~[~"$", res.unwrap().len().to_str(), ~"\r\n"]).to_bytes();
                vec::push_all(&mut output, *res.unwrap());
                vec::push_all(&mut output, "\r\n".to_bytes());
            } else {
                output = "$-1\r\n".to_bytes();
            }
        }
    } else if command == ~"set" {
        do arc.write() |data| {
            args.truncate(3);
            let val = args.pop();
            let key = args.pop();
            data.insert(key, val);

            output = "+OK\r\n".to_bytes();
        }
    } else {
        output = fmt!("-ERR unknown command '%s'\r\n", command).to_bytes();
    }

    output
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]
#[macro_use]
extern crate quote;
extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use std::{env, path::Path};
use syn::{Data, DeriveInput, Fields, Lit, Meta, MetaNameValue};

fn embedded(ident: &syn::Ident, folder_path: String, prefix: Option<&str>) -> TokenStream2 {
  extern crate rust_embed_utils;

  let mut match_values = Vec::<TokenStream2>::new();
  let mut list_values = Vec::<String>::new();

  for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(folder_path) {
    match_values.push(embed_file(&rel_path, &full_canonical_path));

    list_values.push(if let Some(prefix) = prefix {
      format!("{}{}", prefix, rel_path)
    } else {
      rel_path
    });
  }

  let array_len = list_values.len();

  // If debug-embed is on, unconditionally include the code below. Otherwise,
  // make it conditional on cfg(not(debug_assertions)).
  let not_debug_attr = if cfg!(feature = "debug-embed") {
    quote! {}
  } else {
    quote! { #[cfg(not(debug_assertions))]}
  };

  let handle_prefix = if let Some(prefix) = prefix {
    quote! {
      let file_path = file_path.strip_prefix(#prefix)?;
    }
  } else {
    TokenStream2::new()
  };

  quote! {
      #not_debug_attr
      impl #ident {
          pub fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
            #handle_prefix
            match file_path.replace("\\", "/").as_str() {
                #(#match_values)*
                _ => None,
            }
          }

          fn names() -> std::slice::Iter<'static, &'static str> {
              const items: [&str; #array_len] = [#(#list_values),*];
              items.iter()
          }

          pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
              Self::names().map(|x| std::borrow::Cow::from(*x))
          }
      }

      #not_debug_attr
      impl rust_embed::RustEmbed for #ident {
        fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
          #ident::get(file_path)
        }
        fn iter() -> rust_embed::Filenames {
          rust_embed::Filenames::Embedded(#ident::names())
        }
      }
  }
}

fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>) -> TokenStream2 {
  let (handle_prefix, map_iter) = if let Some(prefix) = prefix {
    (
      quote! { let file_path = file_path.strip_prefix(#prefix)?; },
      quote! { std::borrow::Cow::Owned(format!("{}{}", #prefix, e.rel_path)) },
    )
  } else {
    (TokenStream2::new(), quote! { std::borrow::Cow::from(e.rel_path) })
  };

  quote! {
      #[cfg(debug_assertions)]
      impl #ident {
          pub fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
              use std::fs;
              use std::path::Path;

              #handle_prefix

              let file_path = Path::new(#folder_path).join(file_path.replace("\\", "/"));
              match fs::read(file_path) {
                  Ok(contents) => Some(std::borrow::Cow::from(contents)),
                  Err(_e) =>  {
                      return None
                  }
              }
          }

          pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
              use std::path::Path;
              rust_embed::utils::get_files(String::from(#folder_path))
                  .map(|e| #map_iter)
          }
      }

      #[cfg(debug_assertions)]
      impl rust_embed::RustEmbed for #ident {
        fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
          #ident::get(file_path)
        }
        fn iter() -> rust_embed::Filenames {
          // the return type of iter() is unnamable, so we have to box it
          rust_embed::Filenames::Dynamic(Box::new(#ident::iter()))
        }
      }
  }
}

fn generate_assets(ident: &syn::Ident, folder_path: String, prefix: Option<String>) -> TokenStream2 {
  let embedded_impl = embedded(ident, folder_path.clone(), prefix.as_deref());
  if cfg!(feature = "debug-embed") {
    return embedded_impl;
  }

  let dynamic_impl = dynamic(ident, folder_path, prefix.as_deref());

  quote! {
      #embedded_impl
      #dynamic_impl
  }
}

#[cfg(not(feature = "compression"))]
fn embed_file(match_str: &str, full_canonical_path: &str) -> TokenStream2 {
  quote! {
    #match_str => {
        let bytes = &include_bytes!(#full_canonical_path)[..];
        Some(std::borrow::Cow::from(bytes))
    },
  }
}

#[cfg(feature = "compression")]
fn embed_file(rel_path: &str, full_canonical_path: &str) -> TokenStream2 {
  quote! {
    #rel_path => {
        rust_embed::flate!(static FILE: [u8] from #full_canonical_path);

        let bytes = &FILE[..];
        Some(std::borrow::Cow::from(bytes))
    },
  }
}

/// Find a `name = "value"` attribute from the derive input
fn find_attribute_value(ast: &syn::DeriveInput, attr_name: &str) -> Option<String> {
  ast
    .attrs
    .iter()
    .find(|value| value.path.is_ident(attr_name))
    .and_then(|attr| attr.parse_meta().ok())
    .and_then(|meta| match meta {
      Meta::NameValue(MetaNameValue { lit: Lit::Str(val), .. }) => Some(val.value()),
      _ => None,
    })
}

fn impl_rust_embed(ast: &syn::DeriveInput) -> TokenStream2 {
  match ast.data {
    Data::Struct(ref data) => match data.fields {
      Fields::Unit => {}
      _ => panic!("RustEmbed can only be derived for unit structs"),
    },
    _ => panic!("RustEmbed can only be derived for unit structs"),
  };

  let folder_path = find_attribute_value(ast, "folder").expect("#[derive(RustEmbed)] should contain one attribute like this #[folder = \"examples/public/\"]");
  let prefix = find_attribute_value(ast, "prefix");

  #[cfg(feature = "interpolate-folder-path")]
  let folder_path = shellexpand::full(&folder_path).unwrap().to_string();

  // Base relative paths on the Cargo.toml location
  let folder_path = if Path::new(&folder_path).is_relative() {
    Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap())
      .join(folder_path)
      .to_str()
      .unwrap()
      .to_owned()
  } else {
    folder_path
  };

  if !Path::new(&folder_path).exists() {
    let mut message = format!(
      "#[derive(RustEmbed)] folder '{}' does not exist. cwd: '{}'",
      folder_path,
      std::env::current_dir().unwrap().to_str().unwrap()
    );

    // Add a message about the interpolate-folder-path feature if the path may
    // include a variable
    if folder_path.contains('$') && cfg!(not(feature = "interpolate-folder-path")) {
      message += "\nA variable has been detected. RustEmbed can expand variables \
                  when the `interpolate-folder-path` feature is enabled.";
    }

    panic!(message);
  };

  generate_assets(&ast.ident, folder_path, prefix)
}

#[proc_macro_derive(RustEmbed, attributes(folder, prefix))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
  let ast: DeriveInput = syn::parse(input).unwrap();
  let gen = impl_rust_embed(&ast);
  gen.into()
}
<commit_msg>Undo the renaming of a function param<commit_after>#![recursion_limit = "1024"]
#[macro_use]
extern crate quote;
extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use std::{env, path::Path};
use syn::{Data, DeriveInput, Fields, Lit, Meta, MetaNameValue};

fn embedded(ident: &syn::Ident, folder_path: String, prefix: Option<&str>) -> TokenStream2 {
  extern crate rust_embed_utils;

  let mut match_values = Vec::<TokenStream2>::new();
  let mut list_values = Vec::<String>::new();

  for rust_embed_utils::FileEntry { rel_path, full_canonical_path } in rust_embed_utils::get_files(folder_path) {
    match_values.push(embed_file(&rel_path, &full_canonical_path));

    list_values.push(if let Some(prefix) = prefix {
      format!("{}{}", prefix, rel_path)
    } else {
      rel_path
    });
  }

  let array_len = list_values.len();

  // If debug-embed is on, unconditionally include the code below. Otherwise,
  // make it conditional on cfg(not(debug_assertions)).
  let not_debug_attr = if cfg!(feature = "debug-embed") {
    quote! {}
  } else {
    quote! { #[cfg(not(debug_assertions))]}
  };

  let handle_prefix = if let Some(prefix) = prefix {
    quote! {
      let file_path = file_path.strip_prefix(#prefix)?;
    }
  } else {
    TokenStream2::new()
  };

  quote! {
      #not_debug_attr
      impl #ident {
          pub fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
            #handle_prefix
            match file_path.replace("\\", "/").as_str() {
                #(#match_values)*
                _ => None,
            }
          }

          fn names() -> std::slice::Iter<'static, &'static str> {
              const items: [&str; #array_len] = [#(#list_values),*];
              items.iter()
          }

          pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
              Self::names().map(|x| std::borrow::Cow::from(*x))
          }
      }

      #not_debug_attr
      impl rust_embed::RustEmbed for #ident {
        fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
          #ident::get(file_path)
        }
        fn iter() -> rust_embed::Filenames {
          rust_embed::Filenames::Embedded(#ident::names())
        }
      }
  }
}

fn dynamic(ident: &syn::Ident, folder_path: String, prefix: Option<&str>) -> TokenStream2 {
  let (handle_prefix, map_iter) = if let Some(prefix) = prefix {
    (
      quote! { let file_path = file_path.strip_prefix(#prefix)?; },
      quote! { std::borrow::Cow::Owned(format!("{}{}", #prefix, e.rel_path)) },
    )
  } else {
    (TokenStream2::new(), quote! { std::borrow::Cow::from(e.rel_path) })
  };

  quote! {
      #[cfg(debug_assertions)]
      impl #ident {
          pub fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
              use std::fs;
              use std::path::Path;

              #handle_prefix

              let file_path = Path::new(#folder_path).join(file_path.replace("\\", "/"));
              match fs::read(file_path) {
                  Ok(contents) => Some(std::borrow::Cow::from(contents)),
                  Err(_e) =>  {
                      return None
                  }
              }
          }

          pub fn iter() -> impl Iterator<Item = std::borrow::Cow<'static, str>> {
              use std::path::Path;
              rust_embed::utils::get_files(String::from(#folder_path))
                  .map(|e| #map_iter)
          }
      }

      #[cfg(debug_assertions)]
      impl rust_embed::RustEmbed for #ident {
        fn get(file_path: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
          #ident::get(file_path)
        }
        fn iter() -> rust_embed::Filenames {
          // the return type of iter() is unnamable, so we have to box it
          rust_embed::Filenames::Dynamic(Box::new(#ident::iter()))
        }
      }
  }
}

fn generate_assets(ident: &syn::Ident, folder_path: String, prefix: Option<String>) -> TokenStream2 {
  let embedded_impl = embedded(ident, folder_path.clone(), prefix.as_deref());
  if cfg!(feature = "debug-embed") {
    return embedded_impl;
  }

  let dynamic_impl = dynamic(ident, folder_path, prefix.as_deref());

  quote! {
      #embedded_impl
      #dynamic_impl
  }
}

#[cfg(not(feature = "compression"))]
fn embed_file(rel_path: &str, full_canonical_path: &str) -> TokenStream2 {
  quote! {
    #rel_path => {
        let bytes = &include_bytes!(#full_canonical_path)[..];
        Some(std::borrow::Cow::from(bytes))
    },
  }
}

#[cfg(feature = "compression")]
fn embed_file(rel_path: &str, full_canonical_path: &str) -> TokenStream2 {
  quote! {
    #rel_path => {
        rust_embed::flate!(static FILE: [u8] from #full_canonical_path);

        let bytes = &FILE[..];
        Some(std::borrow::Cow::from(bytes))
    },
  }
}

/// Find a `name = "value"` attribute from the derive input
fn find_attribute_value(ast: &syn::DeriveInput, attr_name: &str) -> Option<String> {
  ast
    .attrs
    .iter()
    .find(|value| value.path.is_ident(attr_name))
    .and_then(|attr| attr.parse_meta().ok())
    .and_then(|meta| match meta {
      Meta::NameValue(MetaNameValue { lit: Lit::Str(val), .. }) => Some(val.value()),
      _ => None,
    })
}

fn impl_rust_embed(ast: &syn::DeriveInput) -> TokenStream2 {
  match ast.data {
    Data::Struct(ref data) => match data.fields {
      Fields::Unit => {}
      _ => panic!("RustEmbed can only be derived for unit structs"),
    },
    _ => panic!("RustEmbed can only be derived for unit structs"),
  };

  let folder_path = find_attribute_value(ast, "folder").expect("#[derive(RustEmbed)] should contain one attribute like this #[folder = \"examples/public/\"]");
  let prefix = find_attribute_value(ast, "prefix");

  #[cfg(feature = "interpolate-folder-path")]
  let folder_path = shellexpand::full(&folder_path).unwrap().to_string();

  // Base relative paths on the Cargo.toml location
  let folder_path = if Path::new(&folder_path).is_relative() {
    Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap())
      .join(folder_path)
      .to_str()
      .unwrap()
      .to_owned()
  } else {
    folder_path
  };

  if !Path::new(&folder_path).exists() {
    let mut message = format!(
      "#[derive(RustEmbed)] folder '{}' does not exist. cwd: '{}'",
      folder_path,
      std::env::current_dir().unwrap().to_str().unwrap()
    );

    // Add a message about the interpolate-folder-path feature if the path may
    // include a variable
    if folder_path.contains('$') && cfg!(not(feature = "interpolate-folder-path")) {
      message += "\nA variable has been detected. RustEmbed can expand variables \
                  when the `interpolate-folder-path` feature is enabled.";
    }

    panic!(message);
  };

  generate_assets(&ast.ident, folder_path, prefix)
}

#[proc_macro_derive(RustEmbed, attributes(folder, prefix))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
  let ast: DeriveInput = syn::parse(input).unwrap();
  let gen = impl_rust_embed(&ast);
  gen.into()
}
<|endoftext|>


<commit_before>//!
//! Support mapping based Minkowski Sum geometry. Note thas the support mapping function will
//! ignore the transformation matrix (the first argument of the `support_point` method).
//!

use std::num::{Zero, One};
use std::cmp::ApproxEq;
use nalgebra::na::{Dot, Norm, Vec, AlgebraicVec, Dim, Identity};
use nalgebra::na;
use geom::{Reflection, Implicit, HasMargin};

/// Type of an implicit representation of the Configuration Space Obstacle
/// formed by two geometric objects.
pub type CSO<'self, M, G1, G2> = MinkowskiSum<'self, M, G1, Reflection<'self, G2>>;
pub type AnnotatedCSO<'self, M, G1, G2> = AnnotatedMinkowskiSum<'self, M, G1, Reflection<'self, G2>>;

/**
 * Implicit representation of the minkowski sum of two geometries.
 * The only way to obtain the sum points is to use its support mapping
 * function.
 *
 *  - `G1`: type of the first object involved on the sum.
 *  - `G2`: type of the second object involved on the sum.
 */
#[deriving(Eq, ToStr, Clone)]
pub struct MinkowskiSum<'self, M, G1, G2> {
    priv m1: &'self M,
    priv g1: &'self G1,
    priv m2: &'self M,
    priv g2: &'self G2
}

impl<'self, M, G1, G2> MinkowskiSum<'self, M, G1, G2> {
    /**
     * Builds the Minkowski sum of two geometries. Since the representation is
     * implicit, this is done in constant time.
     */
    #[inline]
    pub fn new(m1: &'self M,
               g1: &'self G1,
               m2: &'self M,
               g2: &'self G2)
               -> MinkowskiSum<'self, M, G1, G2> {
        MinkowskiSum { m1: m1, g1: g1, m2: m2, g2: g2 }
    }
}

impl<'self, N: Add<N, N>, M, G1: HasMargin<N>, G2: HasMargin<N>>
HasMargin<N> for MinkowskiSum<'self, M, G1, G2> {
    #[inline]
    fn margin(&self) -> N {
        self.g1.margin() + self.g2.margin()
    }

}

impl<'self,
     N: Num + Algebraic,
     V: AlgebraicVec<N>,
     M,
     G1: Implicit<N, V, M>,
     G2: Implicit<N, V, M>>
Implicit<N, V, Identity> for MinkowskiSum<'self, M, G1, G2> {
    #[inline]
    fn support_point(&self, _: &Identity, dir: &V) -> V {
        self.g1.support_point(self.m1, dir) + self.g2.support_point(self.m2, dir)
    }

    #[inline]
    fn support_point_without_margin(&self, _: &Identity, dir: &V) -> V {
        self.g1.support_point_without_margin(self.m1, dir) +
        self.g2.support_point_without_margin(self.m2, dir)
    }
}

/**
 * Same as the MinkowskiSum but with a support mapping which keeps track of the
 * original supports points from the two wrapped geometries.
 *  - `G1`: type of the first object involved on the sum.
 *  - `G2`: type of the second object involved on the sum.
 */
#[deriving(Eq, ToStr, Clone)]
pub struct AnnotatedMinkowskiSum<'self, M, G1, G2> {
    priv m1: &'self M,
    priv g1: &'self G1,
    priv m2: &'self M,
    priv g2: &'self G2
}

impl<'self, M, G1, G2> AnnotatedMinkowskiSum<'self, M, G1, G2> {
    /**
     * Builds the Minkowski sum of two geometries. Since the representation is
     * implicit, this is done in constant time.
     */
    #[inline]
    pub fn new(m1: &'self M,
               g1: &'self G1,
               m2: &'self M,
               g2: &'self G2) -> AnnotatedMinkowskiSum<'self, M, G1, G2> {
        AnnotatedMinkowskiSum { m1: m1, g1: g1, m2: m2, g2: g2 }
    }
}

impl<'self, N: Add<N, N>, M, G1: HasMargin<N>, G2: HasMargin<N>>
HasMargin<N> for AnnotatedMinkowskiSum<'self, M, G1, G2> {
    #[inline]
    fn margin(&self) -> N {
        self.g1.margin() + self.g2.margin()
    }
}

impl<'self,
     N: Algebraic + Num,
     V: AlgebraicVec<N> + Clone,
     M,
     G1: Implicit<N, V, M>,
     G2: Implicit<N, V, M>>
Implicit<N, AnnotatedPoint<V>, Identity> for AnnotatedMinkowskiSum<'self, M, G1, G2> {
    #[inline]
    fn support_point(&self, _: &Identity, dir: &AnnotatedPoint<V>) -> AnnotatedPoint<V> {
        let orig1 = self.g1.support_point(self.m1, dir.point());
        let orig2 = self.g2.support_point(self.m2, dir.point());
        let point = orig1 + orig2;

        AnnotatedPoint::new(orig1, orig2, point)
    }

    #[inline]
    fn support_point_without_margin(&self,
                                    _:   &Identity,
                                    dir: &AnnotatedPoint<V>)
                                    -> AnnotatedPoint<V> {
        let orig1 = self.g1.support_point_without_margin(self.m1, dir.point());
        let orig2 = self.g2.support_point_without_margin(self.m2, dir.point());
        let point = orig1 + orig2;

        AnnotatedPoint::new(orig1, orig2, point)
    }
}

// FIXME: AnnotatedPoint is not a good name.
#[doc(hidden)]
#[deriving(Clone, ToStr, Encodable, Decodable)]
pub struct AnnotatedPoint<V> {
    priv orig1: V,
    priv orig2: V,
    priv point: V
}

impl<V> AnnotatedPoint<V> {
    #[doc(hidden)]
    #[inline]
    pub fn new(orig1: V, orig2: V, point: V) -> AnnotatedPoint<V> {
        AnnotatedPoint {
            orig1: orig1,
            orig2: orig2,
            point: point
        }
    }

    #[doc(hidden)]
    #[inline]
    pub fn point<'r>(&'r self) -> &'r V {
        &'r self.point
    }

    #[doc(hidden)]
    #[inline]
    pub fn orig1<'r>(&'r self) -> &'r V {
        &'r self.orig1
    }

    #[doc(hidden)]
    #[inline]
    pub fn orig2<'r>(&'r self) -> &'r V {
        &'r self.orig2
    }
}

impl<V: Zero> AnnotatedPoint<V> {
    #[doc(hidden)]
    #[inline]
    pub fn new_invalid(point: V) -> AnnotatedPoint<V> {
        AnnotatedPoint {
            orig1: Zero::zero::(),
            orig2: Zero::zero::(),
            point: point
        }
    }
}

impl<V: Zero> Zero for AnnotatedPoint<V> {
    #[inline]
    fn zero() -> AnnotatedPoint<V> {
        AnnotatedPoint::new(Zero::zero(), Zero::zero(), Zero::zero())
    }

    #[inline]
    fn is_zero(&self) -> bool {
        self.point.is_zero()
    }
}

impl<V: One> One for AnnotatedPoint<V> {
    // FIXME: this definition works but is flawed (orig1 + orig2 != point)
    #[inline]
    fn one() -> AnnotatedPoint<V> {
        AnnotatedPoint::new(One::one(), One::one(), One::one())
    }
}

impl<V: Sub<V, V>> Sub<AnnotatedPoint<V>, AnnotatedPoint<V>> for
AnnotatedPoint<V> {
    #[inline]
    fn sub(&self, other: &AnnotatedPoint<V>) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(self.orig1 - other.orig1,
        self.orig2 - other.orig2,
        self.point - other.point)
    }
}

impl<V: Add<V, V>> Add<AnnotatedPoint<V>, AnnotatedPoint<V>> for
AnnotatedPoint<V> {
    #[inline]
    fn add(&self, other: &AnnotatedPoint<V>) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(self.orig1 + other.orig1,
        self.orig2 + other.orig2,
        self.point + other.point)
    }
}

impl<V: Neg<V>> Neg<AnnotatedPoint<V>> for AnnotatedPoint<V> {
    #[inline]
    fn neg(&self) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(-self.orig1, -self.orig2, -self.point)
    }
}

impl<V: Dim> Dim for AnnotatedPoint<V> {
    #[inline]
    fn dim(_: Option<AnnotatedPoint<V>>) -> uint {
        na::dim::<V>()
    }
}

impl<V: Vec<N>, N> Dot<N> for AnnotatedPoint<V> {
    #[inline]
    fn dot(a: &AnnotatedPoint<V>, b: &AnnotatedPoint<V>) -> N {
        na::dot(&a.point, &b.point)
    }

    #[inline]
    fn sub_dot(a: &AnnotatedPoint<V>, b: &AnnotatedPoint<V>, c: &AnnotatedPoint<V>) -> N {
        na::sub_dot(&a.point, &b.point, &c.point)
    }
}

impl<N: Algebraic, V: Norm<N> + Clone> Norm<N> for AnnotatedPoint<V> {
    #[inline]
    fn norm(v: &AnnotatedPoint<V>) -> N {
        na::norm(&v.point)
    }

    #[inline]
    fn sqnorm(v: &AnnotatedPoint<V>) -> N {
        na::sqnorm(&v.point)
    }

    /// Be careful: only the `point` is normalized, not `orig1` nor `orig2`.
    #[inline]
    fn normalize_cpy(v: &AnnotatedPoint<V>) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(v.orig1.clone(), v.orig2.clone(), na::normalize(&v.point))
    }

    /// Be careful: only the `point` is normalized, not `orig1` nor `orig2`.
    #[inline]
    fn normalize(&mut self) -> N {
        self.point.normalize()
    }
}

impl<V: Div<N, V>, N> Div<N, AnnotatedPoint<V>> for AnnotatedPoint<V> {
    #[inline]
    fn div(&self, n: &N) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(self.orig1 / *n, self.orig2 / *n, self.point / *n)
    }
}

impl<V: Mul<N, V>, N> Mul<N, AnnotatedPoint<V>> for AnnotatedPoint<V> {
    #[inline]
    fn mul(&self, n: &N) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(self.orig1 * *n, self.orig2 * *n, self.point * *n)
    }
}

impl<V: Eq> Eq for AnnotatedPoint<V> {
    #[inline]
    fn eq(&self, other: &AnnotatedPoint<V>) -> bool {
        self.point == other.point
    }

    #[inline]
    fn ne(&self, other: &AnnotatedPoint<V>) -> bool {
        self.point != other.point
    }
}

/// Computes the support point of a CSO on a given direction.
/// The result is a support point with informations about how it has been constructed.
pub fn cso_support_point<G1: Implicit<N, V, M>,
                         G2: Implicit<N, V, M>,
                         N:  Algebraic + Num,
                         V:  AlgebraicVec<N> + Clone,
                         M>(
                         m1:  &M,
                         g1:  &G1,
                         m2:  &M,
                         g2:  &G2,
                         dir: V)
                         -> AnnotatedPoint<V> {
    let rg2 = Reflection::new(g2);
    let cso = AnnotatedMinkowskiSum::new(m1, g1, m2, &rg2);

    cso.support_point(&Identity::new(), &AnnotatedPoint::new_invalid(dir))
}

/// Computes the support point of a CSO on a given direction.
/// The result is a support point with informations about how it has been constructed.
pub fn cso_support_point_without_margin<G1: Implicit<N, V, M>,
                                        G2: Implicit<N, V, M>,
                                        N:  Algebraic + Num,
                                        V:  AlgebraicVec<N> + Clone,
                                        M>(
                                        m1:  &M,
                                        g1:  &G1,
                                        m2:  &M,
                                        g2:  &G2,
                                        dir: V)
                                        -> AnnotatedPoint<V> {
    let rg2 = Reflection::new(g2);
    let cso = AnnotatedMinkowskiSum::new(m1, g1, m2, &rg2);

    cso.support_point_without_margin(&Identity::new(), &AnnotatedPoint::new_invalid(dir))
}

impl<V: ApproxEq<N>, N: ApproxEq<N>> ApproxEq<N> for AnnotatedPoint<V> {
    #[inline]
    fn approx_epsilon() -> N {
        fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.")
        // ApproxEq::<N>::approx_epsilon()
    }

    #[inline]
    fn approx_eq(&self, other: &AnnotatedPoint<V>) -> bool {
        self.point.approx_eq(&other.point)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &AnnotatedPoint<V>, epsilon: &N) -> bool {
        self.point.approx_eq_eps(&other.point, epsilon)
    }
}
<commit_msg>Update to the last Rust.<commit_after>//!
//! Support mapping based Minkowski Sum geometry. Note thas the support mapping function will
//! ignore the transformation matrix (the first argument of the `support_point` method).
//!

use std::num::{Zero, One};
use std::cmp::ApproxEq;
use nalgebra::na::{Dot, Norm, Vec, AlgebraicVec, Dim, Identity};
use nalgebra::na;
use geom::{Reflection, Implicit, HasMargin};

/// Type of an implicit representation of the Configuration Space Obstacle
/// formed by two geometric objects.
pub type CSO<'self, M, G1, G2> = MinkowskiSum<'self, M, G1, Reflection<'self, G2>>;
pub type AnnotatedCSO<'self, M, G1, G2> = AnnotatedMinkowskiSum<'self, M, G1, Reflection<'self, G2>>;

/**
 * Implicit representation of the minkowski sum of two geometries.
 * The only way to obtain the sum points is to use its support mapping
 * function.
 *
 *  - `G1`: type of the first object involved on the sum.
 *  - `G2`: type of the second object involved on the sum.
 */
#[deriving(Eq, ToStr, Clone)]
pub struct MinkowskiSum<'self, M, G1, G2> {
    priv m1: &'self M,
    priv g1: &'self G1,
    priv m2: &'self M,
    priv g2: &'self G2
}

impl<'self, M, G1, G2> MinkowskiSum<'self, M, G1, G2> {
    /**
     * Builds the Minkowski sum of two geometries. Since the representation is
     * implicit, this is done in constant time.
     */
    #[inline]
    pub fn new(m1: &'self M,
               g1: &'self G1,
               m2: &'self M,
               g2: &'self G2)
               -> MinkowskiSum<'self, M, G1, G2> {
        MinkowskiSum { m1: m1, g1: g1, m2: m2, g2: g2 }
    }
}

impl<'self, N: Add<N, N>, M, G1: HasMargin<N>, G2: HasMargin<N>>
HasMargin<N> for MinkowskiSum<'self, M, G1, G2> {
    #[inline]
    fn margin(&self) -> N {
        self.g1.margin() + self.g2.margin()
    }

}

impl<'self,
     N: Num + Algebraic,
     V: AlgebraicVec<N>,
     M,
     G1: Implicit<N, V, M>,
     G2: Implicit<N, V, M>>
Implicit<N, V, Identity> for MinkowskiSum<'self, M, G1, G2> {
    #[inline]
    fn support_point(&self, _: &Identity, dir: &V) -> V {
        self.g1.support_point(self.m1, dir) + self.g2.support_point(self.m2, dir)
    }

    #[inline]
    fn support_point_without_margin(&self, _: &Identity, dir: &V) -> V {
        self.g1.support_point_without_margin(self.m1, dir) +
        self.g2.support_point_without_margin(self.m2, dir)
    }
}

/**
 * Same as the MinkowskiSum but with a support mapping which keeps track of the
 * original supports points from the two wrapped geometries.
 *  - `G1`: type of the first object involved on the sum.
 *  - `G2`: type of the second object involved on the sum.
 */
#[deriving(Eq, ToStr, Clone)]
pub struct AnnotatedMinkowskiSum<'self, M, G1, G2> {
    priv m1: &'self M,
    priv g1: &'self G1,
    priv m2: &'self M,
    priv g2: &'self G2
}

impl<'self, M, G1, G2> AnnotatedMinkowskiSum<'self, M, G1, G2> {
    /**
     * Builds the Minkowski sum of two geometries. Since the representation is
     * implicit, this is done in constant time.
     */
    #[inline]
    pub fn new(m1: &'self M,
               g1: &'self G1,
               m2: &'self M,
               g2: &'self G2) -> AnnotatedMinkowskiSum<'self, M, G1, G2> {
        AnnotatedMinkowskiSum { m1: m1, g1: g1, m2: m2, g2: g2 }
    }
}

impl<'self, N: Add<N, N>, M, G1: HasMargin<N>, G2: HasMargin<N>>
HasMargin<N> for AnnotatedMinkowskiSum<'self, M, G1, G2> {
    #[inline]
    fn margin(&self) -> N {
        self.g1.margin() + self.g2.margin()
    }
}

impl<'self,
     N: Algebraic + Num,
     V: AlgebraicVec<N> + Clone,
     M,
     G1: Implicit<N, V, M>,
     G2: Implicit<N, V, M>>
Implicit<N, AnnotatedPoint<V>, Identity> for AnnotatedMinkowskiSum<'self, M, G1, G2> {
    #[inline]
    fn support_point(&self, _: &Identity, dir: &AnnotatedPoint<V>) -> AnnotatedPoint<V> {
        let orig1 = self.g1.support_point(self.m1, dir.point());
        let orig2 = self.g2.support_point(self.m2, dir.point());
        let point = orig1 + orig2;

        AnnotatedPoint::new(orig1, orig2, point)
    }

    #[inline]
    fn support_point_without_margin(&self,
                                    _:   &Identity,
                                    dir: &AnnotatedPoint<V>)
                                    -> AnnotatedPoint<V> {
        let orig1 = self.g1.support_point_without_margin(self.m1, dir.point());
        let orig2 = self.g2.support_point_without_margin(self.m2, dir.point());
        let point = orig1 + orig2;

        AnnotatedPoint::new(orig1, orig2, point)
    }
}

// FIXME: AnnotatedPoint is not a good name.
#[doc(hidden)]
#[deriving(Clone, ToStr, Encodable, Decodable)]
pub struct AnnotatedPoint<V> {
    priv orig1: V,
    priv orig2: V,
    priv point: V
}

impl<V> AnnotatedPoint<V> {
    #[doc(hidden)]
    #[inline]
    pub fn new(orig1: V, orig2: V, point: V) -> AnnotatedPoint<V> {
        AnnotatedPoint {
            orig1: orig1,
            orig2: orig2,
            point: point
        }
    }

    #[doc(hidden)]
    #[inline]
    pub fn point<'r>(&'r self) -> &'r V {
        &'r self.point
    }

    #[doc(hidden)]
    #[inline]
    pub fn orig1<'r>(&'r self) -> &'r V {
        &'r self.orig1
    }

    #[doc(hidden)]
    #[inline]
    pub fn orig2<'r>(&'r self) -> &'r V {
        &'r self.orig2
    }
}

impl<V: Zero> AnnotatedPoint<V> {
    #[doc(hidden)]
    #[inline]
    pub fn new_invalid(point: V) -> AnnotatedPoint<V> {
        AnnotatedPoint {
            orig1: na::zero(),
            orig2: na::zero(),
            point: point
        }
    }
}

impl<V: Zero> Zero for AnnotatedPoint<V> {
    #[inline]
    fn zero() -> AnnotatedPoint<V> {
        AnnotatedPoint::new(na::zero(), na::zero(), na::zero())
    }

    #[inline]
    fn is_zero(&self) -> bool {
        self.point.is_zero()
    }
}

impl<V: One> One for AnnotatedPoint<V> {
    // FIXME: this definition works but is flawed (orig1 + orig2 != point)
    #[inline]
    fn one() -> AnnotatedPoint<V> {
        AnnotatedPoint::new(One::one(), One::one(), One::one())
    }
}

impl<V: Sub<V, V>> Sub<AnnotatedPoint<V>, AnnotatedPoint<V>> for
AnnotatedPoint<V> {
    #[inline]
    fn sub(&self, other: &AnnotatedPoint<V>) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(self.orig1 - other.orig1,
        self.orig2 - other.orig2,
        self.point - other.point)
    }
}

impl<V: Add<V, V>> Add<AnnotatedPoint<V>, AnnotatedPoint<V>> for
AnnotatedPoint<V> {
    #[inline]
    fn add(&self, other: &AnnotatedPoint<V>) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(self.orig1 + other.orig1,
        self.orig2 + other.orig2,
        self.point + other.point)
    }
}

impl<V: Neg<V>> Neg<AnnotatedPoint<V>> for AnnotatedPoint<V> {
    #[inline]
    fn neg(&self) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(-self.orig1, -self.orig2, -self.point)
    }
}

impl<V: Dim> Dim for AnnotatedPoint<V> {
    #[inline]
    fn dim(_: Option<AnnotatedPoint<V>>) -> uint {
        na::dim::<V>()
    }
}

impl<V: Vec<N>, N> Dot<N> for AnnotatedPoint<V> {
    #[inline]
    fn dot(a: &AnnotatedPoint<V>, b: &AnnotatedPoint<V>) -> N {
        na::dot(&a.point, &b.point)
    }

    #[inline]
    fn sub_dot(a: &AnnotatedPoint<V>, b: &AnnotatedPoint<V>, c: &AnnotatedPoint<V>) -> N {
        na::sub_dot(&a.point, &b.point, &c.point)
    }
}

impl<N: Algebraic, V: Norm<N> + Clone> Norm<N> for AnnotatedPoint<V> {
    #[inline]
    fn norm(v: &AnnotatedPoint<V>) -> N {
        na::norm(&v.point)
    }

    #[inline]
    fn sqnorm(v: &AnnotatedPoint<V>) -> N {
        na::sqnorm(&v.point)
    }

    /// Be careful: only the `point` is normalized, not `orig1` nor `orig2`.
    #[inline]
    fn normalize_cpy(v: &AnnotatedPoint<V>) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(v.orig1.clone(), v.orig2.clone(), na::normalize(&v.point))
    }

    /// Be careful: only the `point` is normalized, not `orig1` nor `orig2`.
    #[inline]
    fn normalize(&mut self) -> N {
        self.point.normalize()
    }
}

impl<V: Div<N, V>, N> Div<N, AnnotatedPoint<V>> for AnnotatedPoint<V> {
    #[inline]
    fn div(&self, n: &N) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(self.orig1 / *n, self.orig2 / *n, self.point / *n)
    }
}

impl<V: Mul<N, V>, N> Mul<N, AnnotatedPoint<V>> for AnnotatedPoint<V> {
    #[inline]
    fn mul(&self, n: &N) -> AnnotatedPoint<V> {
        AnnotatedPoint::new(self.orig1 * *n, self.orig2 * *n, self.point * *n)
    }
}

impl<V: Eq> Eq for AnnotatedPoint<V> {
    #[inline]
    fn eq(&self, other: &AnnotatedPoint<V>) -> bool {
        self.point == other.point
    }

    #[inline]
    fn ne(&self, other: &AnnotatedPoint<V>) -> bool {
        self.point != other.point
    }
}

/// Computes the support point of a CSO on a given direction.
/// The result is a support point with informations about how it has been constructed.
pub fn cso_support_point<G1: Implicit<N, V, M>,
                         G2: Implicit<N, V, M>,
                         N:  Algebraic + Num,
                         V:  AlgebraicVec<N> + Clone,
                         M>(
                         m1:  &M,
                         g1:  &G1,
                         m2:  &M,
                         g2:  &G2,
                         dir: V)
                         -> AnnotatedPoint<V> {
    let rg2 = Reflection::new(g2);
    let cso = AnnotatedMinkowskiSum::new(m1, g1, m2, &rg2);

    cso.support_point(&Identity::new(), &AnnotatedPoint::new_invalid(dir))
}

/// Computes the support point of a CSO on a given direction.
/// The result is a support point with informations about how it has been constructed.
pub fn cso_support_point_without_margin<G1: Implicit<N, V, M>,
                                        G2: Implicit<N, V, M>,
                                        N:  Algebraic + Num,
                                        V:  AlgebraicVec<N> + Clone,
                                        M>(
                                        m1:  &M,
                                        g1:  &G1,
                                        m2:  &M,
                                        g2:  &G2,
                                        dir: V)
                                        -> AnnotatedPoint<V> {
    let rg2 = Reflection::new(g2);
    let cso = AnnotatedMinkowskiSum::new(m1, g1, m2, &rg2);

    cso.support_point_without_margin(&Identity::new(), &AnnotatedPoint::new_invalid(dir))
}

impl<V: ApproxEq<N>, N: ApproxEq<N>> ApproxEq<N> for AnnotatedPoint<V> {
    #[inline]
    fn approx_epsilon() -> N {
        fail!("approx_epsilon is broken since rust revision 8693943676487c01fa09f5f3daf0df6a1f71e24d.")
        // ApproxEq::<N>::approx_epsilon()
    }

    #[inline]
    fn approx_eq(&self, other: &AnnotatedPoint<V>) -> bool {
        self.point.approx_eq(&other.point)
    }

    #[inline]
    fn approx_eq_eps(&self, other: &AnnotatedPoint<V>, epsilon: &N) -> bool {
        self.point.approx_eq_eps(&other.point, epsilon)
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! Constructs useful in infix operator parsing with the precedence climbing method.

use std::borrow::Cow;
use std::iter::Peekable;
use std::ops::BitOr;

use iterators::Pair;
use RuleType;

/// Macro for more convenient const fn definition of `prec_climber::PrecClimber`.
///
/// # Examples
///
/// ```
/// # use pest::prec_climber::{Assoc, PrecClimber};
/// # use pest::prec_climber;
/// # #[allow(non_camel_case_types)]
/// # #[allow(dead_code)]
/// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// # enum Rule {
/// #     plus,
/// #     minus,
/// #     times,
/// #     divide,
/// #     power
/// # }
/// static CLIMBER: PrecClimber<Rule> = prec_climber![
///     L   plus | minus,
///     L   times | divide,
///     R   power,
/// ];
/// ```
#[cfg(feature = "const_prec_climber")]
#[macro_export]
macro_rules! prec_climber {
    (
        $( $assoc:ident $rule:ident $( | $rules:ident )* ),+ $(,)?
    ) => {{
        prec_climber!(
            @precedences { 1u32 }
            $( [ $rule $( $rules )* ] )*
        );

        $crate::prec_climber::PrecClimber::new_const(
            prec_climber!(
                @array
                $( $assoc $rule $(, $assoc $rules )* ),*
            )
        )
    }};

    ( @assoc L ) => { $crate::prec_climber::Assoc::Left };
    ( @assoc R ) => { $crate::prec_climber::Assoc::Right };

    (
        @array
        $(
            $assoc:ident $rule:ident
        ),*
    ) => {
        &[
            $(
                (
                    Rule::$rule,
                    $rule,
                    prec_climber!( @assoc $assoc ),
                )
            ),*
        ]
    };

    (
        @precedences { $precedence:expr }
    ) => {};

    (
        @precedences { $precedence:expr }
        [ $( $rule:ident )* ]
        $( [ $( $rules:ident )* ] )*
    ) => {
        $(
            const $rule: u32 = $precedence;
        )*
        prec_climber!(
            @precedences { 1u32 + $precedence }
            $( [ $( $rules )* ] )*
        );
    };
}

/// Associativity of an [`Operator`].
///
/// [`Operator`]: struct.Operator.html
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Assoc {
    /// Left `Operator` associativity
    Left,
    /// Right `Operator` associativity
    Right,
}

/// Infix operator used in [`PrecClimber`].
///
/// [`PrecClimber`]: struct.PrecClimber.html
#[derive(Debug)]
pub struct Operator<R: RuleType> {
    rule: R,
    assoc: Assoc,
    next: Option<Box<Operator<R>>>,
}

impl<R: RuleType> Operator<R> {
    /// Creates a new `Operator` from a `Rule` and `Assoc`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, Operator};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus
    /// # }
    /// Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Right);
    /// ```
    pub fn new(rule: R, assoc: Assoc) -> Operator<R> {
        Operator {
            rule,
            assoc,
            next: None,
        }
    }
}

impl<R: RuleType> BitOr for Operator<R> {
    type Output = Self;

    fn bitor(mut self, rhs: Self) -> Self {
        fn assign_next<R: RuleType>(op: &mut Operator<R>, next: Operator<R>) {
            if let Some(ref mut child) = op.next {
                assign_next(child, next);
            } else {
                op.next = Some(Box::new(next));
            }
        }

        assign_next(&mut self, rhs);
        self
    }
}

/// List of operators and precedences, which can perform [precedence climbing][1] on infix
/// expressions contained in a [`Pairs`]. The token pairs contained in the `Pairs` should start
/// with a *primary* pair and then alternate between an *operator* and a *primary*.
///
/// [1]: https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method
/// [`Pairs`]: ../iterators/struct.Pairs.html
#[derive(Debug)]
pub struct PrecClimber<R: Clone + 'static> {
    ops: Cow<'static, [(R, u32, Assoc)]>,
}

#[cfg(feature = "const_prec_climber")]
impl<R: Clone + 'static> PrecClimber<R> {
    /// Creates a new `PrecClimber` directly from a static slice of
    /// `(rule: Rule, precedence: u32, associativity: Assoc)` tuples.
    ///
    /// Precedence starts from `1`.  Entries don't have to be ordered in any way, but it's easier to read when
    /// sorted.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, PrecClimber};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus,
    /// #     times,
    /// #     divide,
    /// #     power
    /// # }
    /// static CLIMBER: PrecClimber<Rule> = PrecClimber::new_const(&[
    ///     (Rule::plus, 1, Assoc::Left), (Rule::minus, 1, Assoc::Left),
    ///     (Rule::times, 2, Assoc::Left), (Rule::divide, 2, Assoc::Left),
    ///     (Rule::power, 3, Assoc::Right)
    /// ]);
    /// ```
    pub const fn new_const(ops: &'static [(R, u32, Assoc)]) -> PrecClimber<R> {
        PrecClimber {
            ops: Cow::Borrowed(ops),
        }
    }
}

impl<R: RuleType> PrecClimber<R> {
    // find matching operator by `rule`
    fn get(&self, rule: &R) -> Option<(u32, Assoc)> {
        self.ops
            .iter()
            .find(|(r, _, _)| r == rule)
            .map(|(_, precedence, assoc)| (*precedence, *assoc))
    }

    /// Creates a new `PrecClimber` from the `Operator`s contained in `ops`. Every entry in the
    /// `Vec` has precedence *index + 1*. In order to have operators with same precedence, they need
    /// to be chained with `|` between them.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, Operator, PrecClimber};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus,
    /// #     times,
    /// #     divide,
    /// #     power
    /// # }
    /// PrecClimber::new(vec![
    ///     Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Left),
    ///     Operator::new(Rule::times, Assoc::Left) | Operator::new(Rule::divide, Assoc::Left),
    ///     Operator::new(Rule::power, Assoc::Right)
    /// ]);
    /// ```
    pub fn new(ops: Vec<Operator<R>>) -> PrecClimber<R> {
        let ops = ops
            .into_iter()
            .zip(1..)
            .fold(Vec::new(), |mut vec, (op, prec)| {
                let mut next = Some(op);

                while let Some(op) = next.take() {
                    let Operator {
                        rule,
                        assoc,
                        next: op_next,
                    } = op;

                    vec.push((rule, prec, assoc));
                    next = op_next.map(|op| *op);
                }

                vec
            });

        PrecClimber {
            ops: Cow::Owned(ops),
        }
    }

    /// Performs the precedence climbing algorithm on the `pairs` in a similar manner to map-reduce.
    /// *Primary* pairs are mapped with `primary` and then reduced to one single result with
    /// `infix`.
    ///
    /// # Panics
    ///
    /// Panics will occur when `pairs` is empty or when the alternating *primary*, *operator*,
    /// *primary* order is not respected.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let primary = |pair| {
    ///     consume(pair, climber)
    /// };
    /// let infix = |lhs: i32, op: Pair<Rule>, rhs: i32| {
    ///     match op.rule() {
    ///         Rule::plus => lhs + rhs,
    ///         Rule::minus => lhs - rhs,
    ///         Rule::times => lhs * rhs,
    ///         Rule::divide => lhs / rhs,
    ///         Rule::power => lhs.pow(rhs as u32),
    ///         _ => unreachable!()
    ///     }
    /// };
    ///
    /// let result = climber.climb(pairs, primary, infix);
    /// ```
    pub fn climb<'i, P, F, G, T>(&self, mut pairs: P, mut primary: F, mut infix: G) -> T
    where
        P: Iterator<Item = Pair<'i, R>>,
        F: FnMut(Pair<'i, R>) -> T,
        G: FnMut(T, Pair<'i, R>, T) -> T,
    {
        let lhs = primary(
            pairs
                .next()
                .expect("precedence climbing requires a non-empty Pairs"),
        );
        self.climb_rec(lhs, 0, &mut pairs.peekable(), &mut primary, &mut infix)
    }

    fn climb_rec<'i, P, F, G, T>(
        &self,
        mut lhs: T,
        min_prec: u32,
        pairs: &mut Peekable<P>,
        primary: &mut F,
        infix: &mut G,
    ) -> T
    where
        P: Iterator<Item = Pair<'i, R>>,
        F: FnMut(Pair<'i, R>) -> T,
        G: FnMut(T, Pair<'i, R>, T) -> T,
    {
        while pairs.peek().is_some() {
            let rule = pairs.peek().unwrap().as_rule();
            if let Some((prec, _)) = self.get(&rule) {
                if prec >= min_prec {
                    let op = pairs.next().unwrap();
                    let mut rhs = primary(pairs.next().expect(
                        "infix operator must be followed by \
                         a primary expression",
                    ));

                    while pairs.peek().is_some() {
                        let rule = pairs.peek().unwrap().as_rule();
                        if let Some((new_prec, assoc)) = self.get(&rule) {
                            if new_prec > prec || assoc == Assoc::Right && new_prec == prec {
                                rhs = self.climb_rec(rhs, new_prec, pairs, primary, infix);
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    }

                    lhs = infix(lhs, op, rhs);
                } else {
                    break;
                }
            } else {
                break;
            }
        }

        lhs
    }
}
<commit_msg>silence non_upper_case_globals warnings<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

//! Constructs useful in infix operator parsing with the precedence climbing method.

use std::borrow::Cow;
use std::iter::Peekable;
use std::ops::BitOr;

use iterators::Pair;
use RuleType;

/// Macro for more convenient const fn definition of `prec_climber::PrecClimber`.
///
/// # Examples
///
/// ```
/// # use pest::prec_climber::{Assoc, PrecClimber};
/// # use pest::prec_climber;
/// # #[allow(non_camel_case_types)]
/// # #[allow(dead_code)]
/// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
/// # enum Rule {
/// #     plus,
/// #     minus,
/// #     times,
/// #     divide,
/// #     power
/// # }
/// static CLIMBER: PrecClimber<Rule> = prec_climber![
///     L   plus | minus,
///     L   times | divide,
///     R   power,
/// ];
/// ```
#[cfg(feature = "const_prec_climber")]
#[macro_export]
macro_rules! prec_climber {
    (
        $( $assoc:ident $rule:ident $( | $rules:ident )* ),+ $(,)?
    ) => {{
        prec_climber!(
            @precedences { 1u32 }
            $( [ $rule $( $rules )* ] )*
        );

        $crate::prec_climber::PrecClimber::new_const(
            prec_climber!(
                @array
                $( $assoc $rule $(, $assoc $rules )* ),*
            )
        )
    }};

    ( @assoc L ) => { $crate::prec_climber::Assoc::Left };
    ( @assoc R ) => { $crate::prec_climber::Assoc::Right };

    (
        @array
        $(
            $assoc:ident $rule:ident
        ),*
    ) => {
        &[
            $(
                (
                    Rule::$rule,
                    $rule,
                    prec_climber!( @assoc $assoc ),
                )
            ),*
        ]
    };

    (
        @precedences { $precedence:expr }
    ) => {};

    (
        @precedences { $precedence:expr }
        [ $( $rule:ident )* ]
        $( [ $( $rules:ident )* ] )*
    ) => {
        $(
            #[allow(non_upper_case_globals)]
            const $rule: u32 = $precedence;
        )*
        prec_climber!(
            @precedences { 1u32 + $precedence }
            $( [ $( $rules )* ] )*
        );
    };
}

/// Associativity of an [`Operator`].
///
/// [`Operator`]: struct.Operator.html
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Assoc {
    /// Left `Operator` associativity
    Left,
    /// Right `Operator` associativity
    Right,
}

/// Infix operator used in [`PrecClimber`].
///
/// [`PrecClimber`]: struct.PrecClimber.html
#[derive(Debug)]
pub struct Operator<R: RuleType> {
    rule: R,
    assoc: Assoc,
    next: Option<Box<Operator<R>>>,
}

impl<R: RuleType> Operator<R> {
    /// Creates a new `Operator` from a `Rule` and `Assoc`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, Operator};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus
    /// # }
    /// Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Right);
    /// ```
    pub fn new(rule: R, assoc: Assoc) -> Operator<R> {
        Operator {
            rule,
            assoc,
            next: None,
        }
    }
}

impl<R: RuleType> BitOr for Operator<R> {
    type Output = Self;

    fn bitor(mut self, rhs: Self) -> Self {
        fn assign_next<R: RuleType>(op: &mut Operator<R>, next: Operator<R>) {
            if let Some(ref mut child) = op.next {
                assign_next(child, next);
            } else {
                op.next = Some(Box::new(next));
            }
        }

        assign_next(&mut self, rhs);
        self
    }
}

/// List of operators and precedences, which can perform [precedence climbing][1] on infix
/// expressions contained in a [`Pairs`]. The token pairs contained in the `Pairs` should start
/// with a *primary* pair and then alternate between an *operator* and a *primary*.
///
/// [1]: https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method
/// [`Pairs`]: ../iterators/struct.Pairs.html
#[derive(Debug)]
pub struct PrecClimber<R: Clone + 'static> {
    ops: Cow<'static, [(R, u32, Assoc)]>,
}

#[cfg(feature = "const_prec_climber")]
impl<R: Clone + 'static> PrecClimber<R> {
    /// Creates a new `PrecClimber` directly from a static slice of
    /// `(rule: Rule, precedence: u32, associativity: Assoc)` tuples.
    ///
    /// Precedence starts from `1`.  Entries don't have to be ordered in any way, but it's easier to read when
    /// sorted.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, PrecClimber};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus,
    /// #     times,
    /// #     divide,
    /// #     power
    /// # }
    /// static CLIMBER: PrecClimber<Rule> = PrecClimber::new_const(&[
    ///     (Rule::plus, 1, Assoc::Left), (Rule::minus, 1, Assoc::Left),
    ///     (Rule::times, 2, Assoc::Left), (Rule::divide, 2, Assoc::Left),
    ///     (Rule::power, 3, Assoc::Right)
    /// ]);
    /// ```
    pub const fn new_const(ops: &'static [(R, u32, Assoc)]) -> PrecClimber<R> {
        PrecClimber {
            ops: Cow::Borrowed(ops),
        }
    }
}

impl<R: RuleType> PrecClimber<R> {
    // find matching operator by `rule`
    fn get(&self, rule: &R) -> Option<(u32, Assoc)> {
        self.ops
            .iter()
            .find(|(r, _, _)| r == rule)
            .map(|(_, precedence, assoc)| (*precedence, *assoc))
    }

    /// Creates a new `PrecClimber` from the `Operator`s contained in `ops`. Every entry in the
    /// `Vec` has precedence *index + 1*. In order to have operators with same precedence, they need
    /// to be chained with `|` between them.
    ///
    /// # Examples
    ///
    /// ```
    /// # use pest::prec_climber::{Assoc, Operator, PrecClimber};
    /// # #[allow(non_camel_case_types)]
    /// # #[allow(dead_code)]
    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    /// # enum Rule {
    /// #     plus,
    /// #     minus,
    /// #     times,
    /// #     divide,
    /// #     power
    /// # }
    /// PrecClimber::new(vec![
    ///     Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Left),
    ///     Operator::new(Rule::times, Assoc::Left) | Operator::new(Rule::divide, Assoc::Left),
    ///     Operator::new(Rule::power, Assoc::Right)
    /// ]);
    /// ```
    pub fn new(ops: Vec<Operator<R>>) -> PrecClimber<R> {
        let ops = ops
            .into_iter()
            .zip(1..)
            .fold(Vec::new(), |mut vec, (op, prec)| {
                let mut next = Some(op);

                while let Some(op) = next.take() {
                    let Operator {
                        rule,
                        assoc,
                        next: op_next,
                    } = op;

                    vec.push((rule, prec, assoc));
                    next = op_next.map(|op| *op);
                }

                vec
            });

        PrecClimber {
            ops: Cow::Owned(ops),
        }
    }

    /// Performs the precedence climbing algorithm on the `pairs` in a similar manner to map-reduce.
    /// *Primary* pairs are mapped with `primary` and then reduced to one single result with
    /// `infix`.
    ///
    /// # Panics
    ///
    /// Panics will occur when `pairs` is empty or when the alternating *primary*, *operator*,
    /// *primary* order is not respected.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// let primary = |pair| {
    ///     consume(pair, climber)
    /// };
    /// let infix = |lhs: i32, op: Pair<Rule>, rhs: i32| {
    ///     match op.rule() {
    ///         Rule::plus => lhs + rhs,
    ///         Rule::minus => lhs - rhs,
    ///         Rule::times => lhs * rhs,
    ///         Rule::divide => lhs / rhs,
    ///         Rule::power => lhs.pow(rhs as u32),
    ///         _ => unreachable!()
    ///     }
    /// };
    ///
    /// let result = climber.climb(pairs, primary, infix);
    /// ```
    pub fn climb<'i, P, F, G, T>(&self, mut pairs: P, mut primary: F, mut infix: G) -> T
    where
        P: Iterator<Item = Pair<'i, R>>,
        F: FnMut(Pair<'i, R>) -> T,
        G: FnMut(T, Pair<'i, R>, T) -> T,
    {
        let lhs = primary(
            pairs
                .next()
                .expect("precedence climbing requires a non-empty Pairs"),
        );
        self.climb_rec(lhs, 0, &mut pairs.peekable(), &mut primary, &mut infix)
    }

    fn climb_rec<'i, P, F, G, T>(
        &self,
        mut lhs: T,
        min_prec: u32,
        pairs: &mut Peekable<P>,
        primary: &mut F,
        infix: &mut G,
    ) -> T
    where
        P: Iterator<Item = Pair<'i, R>>,
        F: FnMut(Pair<'i, R>) -> T,
        G: FnMut(T, Pair<'i, R>, T) -> T,
    {
        while pairs.peek().is_some() {
            let rule = pairs.peek().unwrap().as_rule();
            if let Some((prec, _)) = self.get(&rule) {
                if prec >= min_prec {
                    let op = pairs.next().unwrap();
                    let mut rhs = primary(pairs.next().expect(
                        "infix operator must be followed by \
                         a primary expression",
                    ));

                    while pairs.peek().is_some() {
                        let rule = pairs.peek().unwrap().as_rule();
                        if let Some((new_prec, assoc)) = self.get(&rule) {
                            if new_prec > prec || assoc == Assoc::Right && new_prec == prec {
                                rhs = self.climb_rec(rhs, new_prec, pairs, primary, infix);
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    }

                    lhs = infix(lhs, op, rhs);
                } else {
                    break;
                }
            } else {
                break;
            }
        }

        lhs
    }
}
<|endoftext|>