<commit_before>use {IpNet, Ipv4Net, Ipv6Net};
use std::fmt;
use std::net::{Ipv4Addr, Ipv6Addr};
use serde::{self, Serialize, Deserialize, Serializer, Deserializer};
use serde::de::{EnumAccess, Error, VariantAccess, Visitor};

impl Serialize for IpNet {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        if serializer.is_human_readable() {
            match *self {
                IpNet::V4(ref a) => a.serialize(serializer),
                IpNet::V6(ref a) => a.serialize(serializer),
            }
        } else {
            match *self {
                IpNet::V4(ref a) => serializer.serialize_newtype_variant("IpNet", 0, "V4", a),
                IpNet::V6(ref a) => serializer.serialize_newtype_variant("IpNet", 1, "V6", a),
            }
        }
    }
}

impl<'de> Deserialize<'de> for IpNet {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        if deserializer.is_human_readable() {
            struct IpNetVisitor;

            impl<'de> Visitor<'de> for IpNetVisitor {
                type Value = IpNet;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("IPv4 or IPv6 network address")
                }

                fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
                    where E: Error
                {
                    s.parse().map_err(Error::custom)
                }
            }

            deserializer.deserialize_str(IpNetVisitor)
        } else {
            struct EnumVisitor;

            #[derive(Serialize, Deserialize)]
            enum IpNetKind {
                V4,
                V6,
            }

            impl<'de> Visitor<'de> for EnumVisitor {
                type Value = IpNet;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("IPv4 or IPv6 network address")
                }

                fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
                    where A: EnumAccess<'de>
                {
                    match try!(data.variant()) {
                        (IpNetKind::V4, v) => v.newtype_variant().map(IpNet::V4),
                        (IpNetKind::V6, v) => v.newtype_variant().map(IpNet::V6),
                    }
                }
            }

            deserializer.deserialize_enum("IpNet", &["V4", "V6"], EnumVisitor)
        }
    }
}

impl Serialize for Ipv4Net {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        if serializer.is_human_readable() {
            serializer.serialize_str(&self.to_string())
        } else {
            let mut v: [u8; 5] = [0; 5];
            v[0..4].copy_from_slice(&self.octets());
            v[4] = self.prefix_len();
            v.serialize(serializer)
        }
    }
}

impl<'de> Deserialize<'de> for Ipv4Net {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        if deserializer.is_human_readable() {
            struct IpAddrVisitor;

            impl<'de> Visitor<'de> for IpAddrVisitor {
                type Value = Ipv4Net;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("IPv4 network address")
                }

                fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
                    where E: Error
                {
                    s.parse().map_err(Error::custom)
                }
            }

            deserializer.deserialize_str(IpAddrVisitor)
        } else {
            let b = <[u8; 5]>::deserialize(deserializer)?;
            Ipv4Net::new(Ipv4Addr::new(b[0], b[1], b[2], b[3]), b[4]).map_err(serde::de::Error::custom)
        }
    }
}

impl Serialize for Ipv6Net {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        if serializer.is_human_readable() {
            serializer.serialize_str(&self.to_string())
        } else {
            let mut v: [u8; 17] = [0; 17];
            v[0..16].copy_from_slice(&self.octets());
            v[16] = self.prefix_len();
            v.serialize(serializer)
        }
    }
}

impl<'de> Deserialize<'de> for Ipv6Net {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        if deserializer.is_human_readable() {
            struct IpAddrVisitor;

            impl<'de> Visitor<'de> for IpAddrVisitor {
                type Value = Ipv6Net;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("IPv6 network address")
                }

                fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
                    where E: Error
                {
                    s.parse().map_err(Error::custom)
                }
            }

            deserializer.deserialize_str(IpAddrVisitor)
        } else {
            let b = <[u8; 17]>::deserialize(deserializer)?;
            Ipv6Net::new(Ipv6Addr::new(
                ((b[0] as u16) << 8) | b[1] as u16, ((b[2] as u16) << 8) | b[3] as u16,
                ((b[4] as u16) << 8) | b[5] as u16, ((b[6] as u16) << 8) | b[7] as u16,
                ((b[8] as u16) << 8) | b[9] as u16, ((b[10] as u16) << 8) | b[11] as u16,
                ((b[12] as u16) << 8) | b[13] as u16, ((b[14] as u16) << 8) | b[15] as u16
            ), b[16]).map_err(Error::custom)
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate serde_test;

    use {IpNet, Ipv4Net, Ipv6Net};
    use self::serde_test::{assert_tokens, Configure, Token};

    #[test]
    fn test_serialize_ipnet_v4() {
        let net_str = "10.1.1.0/24";
        let net: IpNet = net_str.parse().unwrap();
        assert_tokens(&net.readable(), &[Token::Str(net_str)]);
        assert_tokens(&net.compact(), &[
            Token::NewtypeVariant { name: "IpNet", variant: "V4", },
            Token::Tuple { len: 5 },
            Token::U8(10),
            Token::U8(1),
            Token::U8(1),
            Token::U8(0),
            Token::U8(24),
            Token::TupleEnd,
        ]);
    }

    #[test]
    fn test_serialize_ipnet_v6() {
        let net_str = "fd00::/32";
        let net: IpNet = net_str.parse().unwrap();
        assert_tokens(&net.readable(), &[Token::Str(net_str)]);
        assert_tokens(&net.compact(), &[
            Token::NewtypeVariant { name: "IpNet", variant: "V6", },
            // This is too painful, but Token::Bytes() seems to be
            // an array with a length, which is not what we serialize.
            Token::Tuple { len: 17 },
            Token::U8(253u8),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(32),
            Token::TupleEnd,
        ]);
    }

    #[test]
    fn test_serialize_ipv4_net() {
        let net_str = "10.1.1.0/24";
        let net: Ipv4Net = net_str.parse().unwrap();
        assert_tokens(&net.readable(), &[Token::Str(net_str)]);
        assert_tokens(&net.compact(), &[
            Token::Tuple { len: 5 },
            Token::U8(10),
            Token::U8(1),
            Token::U8(1),
            Token::U8(0),
            Token::U8(24),
            Token::TupleEnd,
        ]);
    }

    #[test]
    fn test_serialize_ipv6_net() {
        let net_str = "fd00::/32";
        let net: Ipv6Net = net_str.parse().unwrap();
        assert_tokens(&net.readable(), &[Token::Str(net_str)]);
        assert_tokens(&net.compact(), &[
            // This is too painful, but Token::Bytes() seems to be
            // an array with a length, which is not what we serialize.
            Token::Tuple { len: 17 },
            Token::U8(253u8),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(32),
            Token::TupleEnd,
        ]);
    }
}<commit_msg>Tidy up serialize to use serialize_tuple()<commit_after>use {IpNet, Ipv4Net, Ipv6Net};
use std::fmt;
use std::net::{Ipv4Addr, Ipv6Addr};
use serde::{self, Serialize, Deserialize, Serializer, Deserializer};
use serde::ser::{SerializeTuple};
use serde::de::{EnumAccess, Error, VariantAccess, Visitor};

impl Serialize for IpNet {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        if serializer.is_human_readable() {
            match *self {
                IpNet::V4(ref a) => a.serialize(serializer),
                IpNet::V6(ref a) => a.serialize(serializer),
            }
        } else {
            match *self {
                IpNet::V4(ref a) => serializer.serialize_newtype_variant("IpNet", 0, "V4", a),
                IpNet::V6(ref a) => serializer.serialize_newtype_variant("IpNet", 1, "V6", a),
            }
        }
    }
}

impl<'de> Deserialize<'de> for IpNet {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        if deserializer.is_human_readable() {
            struct IpNetVisitor;

            impl<'de> Visitor<'de> for IpNetVisitor {
                type Value = IpNet;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("IPv4 or IPv6 network address")
                }

                fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
                    where E: Error
                {
                    s.parse().map_err(Error::custom)
                }
            }

            deserializer.deserialize_str(IpNetVisitor)
        } else {
            struct EnumVisitor;

            #[derive(Serialize, Deserialize)]
            enum IpNetKind {
                V4,
                V6,
            }

            impl<'de> Visitor<'de> for EnumVisitor {
                type Value = IpNet;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("IPv4 or IPv6 network address")
                }

                fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
                    where A: EnumAccess<'de>
                {
                    match try!(data.variant()) {
                        (IpNetKind::V4, v) => v.newtype_variant().map(IpNet::V4),
                        (IpNetKind::V6, v) => v.newtype_variant().map(IpNet::V6),
                    }
                }
            }

            deserializer.deserialize_enum("IpNet", &["V4", "V6"], EnumVisitor)
        }
    }
}

impl Serialize for Ipv4Net {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        if serializer.is_human_readable() {
            serializer.serialize_str(&self.to_string())
        } else {
            let mut seq = serializer.serialize_tuple(5)?;
            for octet in &self.octets() {
                seq.serialize_element(octet)?;
            }
            seq.serialize_element(&self.prefix_len())?;
            seq.end()
        }
    }
}

impl<'de> Deserialize<'de> for Ipv4Net {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        if deserializer.is_human_readable() {
            struct IpAddrVisitor;

            impl<'de> Visitor<'de> for IpAddrVisitor {
                type Value = Ipv4Net;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("IPv4 network address")
                }

                fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
                    where E: Error
                {
                    s.parse().map_err(Error::custom)
                }
            }

            deserializer.deserialize_str(IpAddrVisitor)
        } else {
            let b = <[u8; 5]>::deserialize(deserializer)?;
            Ipv4Net::new(Ipv4Addr::new(b[0], b[1], b[2], b[3]), b[4]).map_err(serde::de::Error::custom)
        }
    }
}

impl Serialize for Ipv6Net {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        if serializer.is_human_readable() {
            serializer.serialize_str(&self.to_string())
        } else {
            let mut seq = serializer.serialize_tuple(17)?;
            for octet in &self.octets() {
                seq.serialize_element(octet)?;
            }
            seq.serialize_element(&self.prefix_len())?;
            seq.end()
        }
    }
}

impl<'de> Deserialize<'de> for Ipv6Net {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        if deserializer.is_human_readable() {
            struct IpAddrVisitor;

            impl<'de> Visitor<'de> for IpAddrVisitor {
                type Value = Ipv6Net;

                fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                    formatter.write_str("IPv6 network address")
                }

                fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
                    where E: Error
                {
                    s.parse().map_err(Error::custom)
                }
            }

            deserializer.deserialize_str(IpAddrVisitor)
        } else {
            let b = <[u8; 17]>::deserialize(deserializer)?;
            Ipv6Net::new(Ipv6Addr::new(
                ((b[0] as u16) << 8) | b[1] as u16, ((b[2] as u16) << 8) | b[3] as u16,
                ((b[4] as u16) << 8) | b[5] as u16, ((b[6] as u16) << 8) | b[7] as u16,
                ((b[8] as u16) << 8) | b[9] as u16, ((b[10] as u16) << 8) | b[11] as u16,
                ((b[12] as u16) << 8) | b[13] as u16, ((b[14] as u16) << 8) | b[15] as u16
            ), b[16]).map_err(Error::custom)
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate serde_test;

    use {IpNet, Ipv4Net, Ipv6Net};
    use self::serde_test::{assert_tokens, Configure, Token};

    #[test]
    fn test_serialize_ipnet_v4() {
        let net_str = "10.1.1.0/24";
        let net: IpNet = net_str.parse().unwrap();
        assert_tokens(&net.readable(), &[Token::Str(net_str)]);
        assert_tokens(&net.compact(), &[
            Token::NewtypeVariant { name: "IpNet", variant: "V4", },
            Token::Tuple { len: 5 },
            Token::U8(10),
            Token::U8(1),
            Token::U8(1),
            Token::U8(0),
            Token::U8(24),
            Token::TupleEnd,
        ]);
    }

    #[test]
    fn test_serialize_ipnet_v6() {
        let net_str = "fd00::/32";
        let net: IpNet = net_str.parse().unwrap();
        assert_tokens(&net.readable(), &[Token::Str(net_str)]);
        assert_tokens(&net.compact(), &[
            Token::NewtypeVariant { name: "IpNet", variant: "V6", },
            // This is too painful, but Token::Bytes() seems to be
            // an array with a length, which is not what we serialize.
            Token::Tuple { len: 17 },
            Token::U8(253u8),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(32),
            Token::TupleEnd,
        ]);
    }

    #[test]
    fn test_serialize_ipv4_net() {
        let net_str = "10.1.1.0/24";
        let net: Ipv4Net = net_str.parse().unwrap();
        assert_tokens(&net.readable(), &[Token::Str(net_str)]);
        assert_tokens(&net.compact(), &[
            Token::Tuple { len: 5 },
            Token::U8(10),
            Token::U8(1),
            Token::U8(1),
            Token::U8(0),
            Token::U8(24),
            Token::TupleEnd,
        ]);
    }

    #[test]
    fn test_serialize_ipv6_net() {
        let net_str = "fd00::/32";
        let net: Ipv6Net = net_str.parse().unwrap();
        assert_tokens(&net.readable(), &[Token::Str(net_str)]);
        assert_tokens(&net.compact(), &[
            // This is too painful, but Token::Bytes() seems to be
            // an array with a length, which is not what we serialize.
            Token::Tuple { len: 17 },
            Token::U8(253u8),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(0),
            Token::U8(32),
            Token::TupleEnd,
        ]);
    }
}<|endoftext|>


<commit_before>use bullet::{BulletDrawable, bullets::Bullets};
use cgmath::Point2;
use character::controls::CharacterInputState;
use critter::CritterData;
use data;
use game::constants::{ASPECT_RATIO, NORMAL_DEATH_SPRITE_OFFSET, SPRITE_OFFSET, VIEW_DISTANCE, ZOMBIE_SHEET_TOTAL_WIDTH, ZOMBIE_STILL_SPRITE_OFFSET};
use game::get_random_bool;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{add_random_offset_to_screen_pos,
               calc_hypotenuse,
               can_move_to_tile,
               camera::CameraInputState, dimensions::{Dimensions, get_projection, get_view_matrix},
               direction,
               direction_movement,
               direction_movement_180,
               GameTime,
               orientation::{Orientation, Stance},
               orientation_to_direction,
               overlaps,
               texture::load_texture};
use shaders::{CharacterSheet, critter_pipeline, Position, Projection, VertexData};
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};
use terrain::path_finding::calc_next_movement;
use zombie::zombies::Zombies;

pub mod zombies;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Debug, Clone)]
pub struct ZombieDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  last_decision: u64,
  pub movement_direction: Point2<f32>,
  zombie_idx: usize,
  zombie_death_idx: usize,
  is_colliding: bool,
  movement_speed: f32,
}

impl ZombieDrawable {
  pub fn new(position: Position) -> ZombieDrawable {
    let view = get_view_matrix(VIEW_DISTANCE);
    let projection = get_projection(view, ASPECT_RATIO);
    ZombieDrawable {
      projection,
      position,
      previous_position: Position::new(0.0, 0.0),
      orientation: Orientation::Left,
      stance: Stance::Still,
      direction: Orientation::Left,
      last_decision: 2,
      movement_direction: Point2::new(0.0, 0.0),
      zombie_idx: 0,
      zombie_death_idx: 0,
      is_colliding: false,
      movement_speed: 0.0,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, game_time: u64) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new(
        ci.x_movement - self.previous_position.position[0],
        ci.y_movement - self.previous_position.position[1]);

    self.previous_position = Position::new(ci.x_movement, ci.y_movement);

    let x_y_distance_to_player = Point2::new(
      self.position.position[0] - offset_delta.position[0],
      self.position.position[1] - offset_delta.position[1]);

    let distance_to_player = calc_hypotenuse(x_y_distance_to_player.x.abs(), x_y_distance_to_player.y.abs());

    let is_alive = self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath;

    if is_alive {
      let zombie_pos = Position::new(ci.x_movement - self.position.position[0], ci.y_movement - self.position.position[1]);

      if distance_to_player < 3.0 {
        let dir = calc_next_movement(zombie_pos, self.previous_position) as f32;
        self.direction = orientation_to_direction(dir);
        self.movement_direction = direction_movement(dir);
        self.stance = Stance::Walking;
        self.movement_speed = 1.4;
      } else {
        self.idle_direction_movement(zombie_pos, game_time);
        self.movement_speed = 1.0;
      }
    } else {
      self.movement_direction = Point2::new(0.0, 0.0);
    }

    self.position = Position::new(
      self.movement_direction.x * self.movement_speed,
      self.movement_direction.y * self.movement_speed) + self.position + offset_delta;
  }

  fn idle_direction_movement(&mut self, zombie_pos: Position, game_time: u64) {
    if !can_move_to_tile(zombie_pos) {
      let dir = direction(Point2::new(0.0, 0.0), self.movement_direction);
      self.movement_direction = direction_movement_180(self.movement_direction);
      self.orientation = orientation_to_direction(dir);
    }

    if self.last_decision + 2 < game_time {
      self.stance = Stance::Walking;
      self.last_decision = game_time;
      let end_point = add_random_offset_to_screen_pos(zombie_pos);
      let dir = calc_next_movement(zombie_pos, end_point) as f32;
      self.movement_direction = direction_movement(dir);
      self.direction = orientation_to_direction(dir);
    }
  }

  fn check_bullet_hits(&mut self, bullets: &[BulletDrawable]) {
    bullets.iter().for_each(|bullet| {
      if overlaps(self.position, bullet.position, 15.0, 15.0) && self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
        self.stance =
          if get_random_bool() {
            Stance::NormalDeath
          } else {
            Stance::CriticalDeath
          };
      }
    });
  }

  pub fn update_alive_idx(&mut self, max_idx: usize) {
    if self.zombie_idx < max_idx {
      self.zombie_idx += 1;
    } else {
      self.zombie_idx = 0;
    }
  }

  pub fn update_death_idx(&mut self, max_idx: usize) {
    if self.zombie_death_idx < max_idx {
      self.zombie_death_idx += 1;
    }
  }
}

pub struct ZombieDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> ZombieDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> ZombieDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let zombie_bytes = include_bytes!("../../assets/zombie.png");

    let vertex_data: [VertexData; 4] = [
      VertexData::new([-25.0, -35.0], [0.0, 1.0]),
      VertexData::new([25.0, -35.0], [1.0, 1.0]),
      VertexData::new([25.0, 35.0], [1.0, 0.0]),
      VertexData::new([-25.0, 35.0], [0.0, 0.0]),
    ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data[..], &index_data[..]);

    let char_texture = load_texture(factory, zombie_bytes);
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              critter_pipeline::new())
      .unwrap();

    let pipeline_data = critter_pipeline::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_zombie();

    ZombieDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, drawable: &mut ZombieDrawable) -> CharacterSheet {
    let zombie_sprite = match drawable.stance {
      Stance::Still => {
        let sprite_idx = (drawable.direction as usize * 4 + drawable.zombie_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::Walking if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::NormalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 6 + drawable.zombie_death_idx + NORMAL_DEATH_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::CriticalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_death_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      _ => {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
    };

    let (y_div, row_idx) =
      if drawable.stance == Stance::NormalDeath || drawable.stance == Stance::CriticalDeath {
        (0.0, 2)
      } else {
        (1.0, 2)
      };

    let elements_x = ZOMBIE_SHEET_TOTAL_WIDTH / (zombie_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div,
      row_idx,
      index: zombie_sprite.1 as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut ZombieDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(&mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::prelude::System<'a> for PreDrawSystem {
  #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
  type SystemData = (WriteStorage<'a, Zombies>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, Bullets>,
                     Read<'a, Dimensions>,
                     Read<'a, GameTime>);

  fn run(&mut self, (mut zombies, camera_input, character_input, bullets, dim, gt): Self::SystemData) {
    use specs::join::Join;

    for (zs, camera, ci, bs) in (&mut zombies, &camera_input, &character_input, &bullets).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for z in &mut zs.zombies {
        z.update(&world_to_clip, ci, gt.0);
        z.check_bullet_hits(&bs.bullets);
      }
    }
  }
}
<commit_msg>Do not prevent zombie attacks<commit_after>use bullet::{BulletDrawable, bullets::Bullets};
use cgmath::Point2;
use character::controls::CharacterInputState;
use critter::CritterData;
use data;
use game::constants::{ASPECT_RATIO, NORMAL_DEATH_SPRITE_OFFSET, SPRITE_OFFSET, VIEW_DISTANCE, ZOMBIE_SHEET_TOTAL_WIDTH, ZOMBIE_STILL_SPRITE_OFFSET};
use game::get_random_bool;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{add_random_offset_to_screen_pos,
               calc_hypotenuse,
               can_move_to_tile,
               camera::CameraInputState, dimensions::{Dimensions, get_projection, get_view_matrix},
               direction,
               direction_movement,
               direction_movement_180,
               GameTime,
               orientation::{Orientation, Stance},
               orientation_to_direction,
               overlaps,
               texture::load_texture};
use shaders::{CharacterSheet, critter_pipeline, Position, Projection, VertexData};
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};
use terrain::path_finding::calc_next_movement;
use zombie::zombies::Zombies;

pub mod zombies;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Debug, Clone)]
pub struct ZombieDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  last_decision: u64,
  pub movement_direction: Point2<f32>,
  zombie_idx: usize,
  zombie_death_idx: usize,
  is_colliding: bool,
  movement_speed: f32,
}

impl ZombieDrawable {
  pub fn new(position: Position) -> ZombieDrawable {
    let view = get_view_matrix(VIEW_DISTANCE);
    let projection = get_projection(view, ASPECT_RATIO);
    ZombieDrawable {
      projection,
      position,
      previous_position: Position::new(0.0, 0.0),
      orientation: Orientation::Left,
      stance: Stance::Still,
      direction: Orientation::Left,
      last_decision: 2,
      movement_direction: Point2::new(0.0, 0.0),
      zombie_idx: 0,
      zombie_death_idx: 0,
      is_colliding: false,
      movement_speed: 0.0,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, game_time: u64) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new(
        ci.x_movement - self.previous_position.position[0],
        ci.y_movement - self.previous_position.position[1]);

    self.previous_position = Position::new(ci.x_movement, ci.y_movement);

    let x_y_distance_to_player = Point2::new(
      self.position.position[0] - offset_delta.position[0],
      self.position.position[1] - offset_delta.position[1]);

    let distance_to_player = calc_hypotenuse(x_y_distance_to_player.x.abs(), x_y_distance_to_player.y.abs());

    let is_alive = self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath;

    if is_alive {
      let zombie_pos = Position::new(ci.x_movement - self.position.position[0], ci.y_movement - self.position.position[1]);

      if distance_to_player < 300.0 {
        let dir = calc_next_movement(zombie_pos, self.previous_position) as f32;
        self.direction = orientation_to_direction(dir);
        self.movement_direction = direction_movement(dir);
        self.stance = Stance::Walking;
        self.movement_speed = 1.4;
      } else {
        self.idle_direction_movement(zombie_pos, game_time);
        self.movement_speed = 1.0;
      }
    } else {
      self.movement_direction = Point2::new(0.0, 0.0);
    }

    self.position = Position::new(
      self.movement_direction.x * self.movement_speed,
      self.movement_direction.y * self.movement_speed) + self.position + offset_delta;
  }

  fn idle_direction_movement(&mut self, zombie_pos: Position, game_time: u64) {
    if !can_move_to_tile(zombie_pos) {
      let dir = direction(Point2::new(0.0, 0.0), self.movement_direction);
      self.movement_direction = direction_movement_180(self.movement_direction);
      self.orientation = orientation_to_direction(dir);
    }

    if self.last_decision + 2 < game_time {
      self.stance = Stance::Walking;
      self.last_decision = game_time;
      let end_point = add_random_offset_to_screen_pos(zombie_pos);
      let dir = calc_next_movement(zombie_pos, end_point) as f32;
      self.movement_direction = direction_movement(dir);
      self.direction = orientation_to_direction(dir);
    }
  }

  fn check_bullet_hits(&mut self, bullets: &[BulletDrawable]) {
    bullets.iter().for_each(|bullet| {
      if overlaps(self.position, bullet.position, 15.0, 15.0) && self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
        self.stance =
          if get_random_bool() {
            Stance::NormalDeath
          } else {
            Stance::CriticalDeath
          };
      }
    });
  }

  pub fn update_alive_idx(&mut self, max_idx: usize) {
    if self.zombie_idx < max_idx {
      self.zombie_idx += 1;
    } else {
      self.zombie_idx = 0;
    }
  }

  pub fn update_death_idx(&mut self, max_idx: usize) {
    if self.zombie_death_idx < max_idx {
      self.zombie_death_idx += 1;
    }
  }
}

pub struct ZombieDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> ZombieDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> ZombieDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let zombie_bytes = include_bytes!("../../assets/zombie.png");

    let vertex_data: [VertexData; 4] = [
      VertexData::new([-25.0, -35.0], [0.0, 1.0]),
      VertexData::new([25.0, -35.0], [1.0, 1.0]),
      VertexData::new([25.0, 35.0], [1.0, 0.0]),
      VertexData::new([-25.0, 35.0], [0.0, 0.0]),
    ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data[..], &index_data[..]);

    let char_texture = load_texture(factory, zombie_bytes);
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              critter_pipeline::new())
      .unwrap();

    let pipeline_data = critter_pipeline::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_zombie();

    ZombieDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, drawable: &mut ZombieDrawable) -> CharacterSheet {
    let zombie_sprite = match drawable.stance {
      Stance::Still => {
        let sprite_idx = (drawable.direction as usize * 4 + drawable.zombie_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::Walking if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::NormalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 6 + drawable.zombie_death_idx + NORMAL_DEATH_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::CriticalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_death_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      _ => {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
    };

    let (y_div, row_idx) =
      if drawable.stance == Stance::NormalDeath || drawable.stance == Stance::CriticalDeath {
        (0.0, 2)
      } else {
        (1.0, 2)
      };

    let elements_x = ZOMBIE_SHEET_TOTAL_WIDTH / (zombie_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div,
      row_idx,
      index: zombie_sprite.1 as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut ZombieDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(&mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::prelude::System<'a> for PreDrawSystem {
  #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
  type SystemData = (WriteStorage<'a, Zombies>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, Bullets>,
                     Read<'a, Dimensions>,
                     Read<'a, GameTime>);

  fn run(&mut self, (mut zombies, camera_input, character_input, bullets, dim, gt): Self::SystemData) {
    use specs::join::Join;

    for (zs, camera, ci, bs) in (&mut zombies, &camera_input, &character_input, &bullets).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for z in &mut zs.zombies {
        z.update(&world_to_clip, ci, gt.0);
        z.check_bullet_hits(&bs.bullets);
      }
    }
  }
}
<|endoftext|>


<commit_before>pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let mut saddle_points = Vec::new();

    let width = input.len();
    let height = input[0].len();

    for i in 0..width {
        for j in 0..height {
            let column = input.iter().map(|x| x[j]).collect::<Vec<u64>>();
            let row = &input[i];

            let max = row.iter().max().unwrap();
            let min = column.iter().min().unwrap();

            let value = input[i][j];

            if value >= *max && value <= *min {
                saddle_points.push((i, j));
            }
        }
    }
    saddle_points
}
<commit_msg>Optimize saddle-points; use idiomatic rust<commit_after>pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let (width, height) = match (input.len(), input[0].len()) {
        (0, _) | (_, 0) => return Vec::new(),
        (n, k) => (n, k),
    };

    let mut saddle_points = Vec::new();

    for i in 0..width {
        let row_max = input[i].iter().max().unwrap();

        for j in 0..height {
            let column_min = input.iter().map(|x| x[j]).min().unwrap();

            let value = input[i][j];

            if value == *row_max && value == column_min {
                saddle_points.push((i, j));
            }
        }
    }

    saddle_points
}
<|endoftext|>


<commit_before>use super::*;

impl Editor {
    /// Goto a given position
    #[inline]
    pub fn goto(&mut self, (x, y): (usize, usize)) {
        self.cursor_mut().x = x;
        self.cursor_mut().y = y;
    }

    /// Get the position of the next char
    #[inline]
    pub fn next_pos(&self) -> (usize, usize) {
        // TODO: Add numerals
        if self.x() == self.text[self.y()].len() {
            if self.y() < self.text.len() - 1 {
                (0, self.y() + 1)
            } else {
                (self.x(), self.y())
            }
        } else {
            (self.x() + 1, self.y())
        }
    }

    /// Get the position of previous char
    #[inline]
    pub fn previous_pos(&self) -> (usize, usize) {
        if self.x() == 0 {
            if self.y() > 0 {
                (self.text[self.y() - 1].len(), self.y() - 1)
            } else {
                (self.x(), self.y())
            }
        } else {
            (self.x() - 1, self.y())
        }
    }

    /// Goto the next char
    #[inline]
    pub fn goto_next(&mut self) {
        let p = self.next_pos();
        self.goto(p);
    }
    /// Goto the previous char
    #[inline]
    pub fn goto_previous(&mut self) {
        let p = self.previous_pos();
        self.goto(p);
    }

    /// Get the position of the right char
    #[inline]
    pub fn right_pos(&self, n: usize) -> (usize, usize) {
        let x = self.x() + n;

        if x > self.text[self.y()].len() {
            (self.text[self.y()].len(), self.y())
        } else {
            (x, self.y())
        }
    }
    /// Goto the right char
    #[inline]
    pub fn goto_right(&mut self, n: usize) {
        self.cursor_mut().x = self.right_pos(n).0;
    }

    /// Get the position of the left char
    #[inline]
    pub fn left_pos(&self, n: usize) -> (usize, usize) {
        if n <= self.x() {
            (self.x() - n, self.y())
        } else {
            (0, self.y())
        }
    }
    /// Goto the left char
    #[inline]
    pub fn goto_left(&mut self, n: usize) {
        self.cursor_mut().x = self.left_pos(n).0;
    }

    /// Get the position of the char above the cursor
    #[inline]
    pub fn up_pos(&self, n: usize) -> (usize, usize) {
        if n <= self.y() {
            (self.cursor().x, self.y() - n)
        } else {
            (self.cursor().x, 0)
        }
    }
    /// Go a char up
    #[inline]
    pub fn goto_up(&mut self, n: usize) {
        let p = self.up_pos(n);
        self.goto(p);
    }

    /// Get the position under the char
    #[inline]
    pub fn down_pos(&self, n: usize) -> (usize, usize) {
        let y = self.y() + n;

        if y >= self.text.len() {
            (self.cursor().x, self.text.len() - 1)
        } else {
            (self.cursor().x, y)
        }
    }

    /// Go down
    #[inline]
    pub fn goto_down(&mut self, n: usize) {
        let p = self.down_pos(n);
        self.goto(p);
    }

    /// Get the position of the end of the line
    #[inline]
    pub fn ln_end_pos(&self) -> (usize, usize) {
        (self.text[self.y()].len(), self.y())
    }

    /// Goto line end
    #[inline]
    pub fn goto_ln_end(&mut self) {
        let p = self.ln_end_pos();
        self.goto(p);
    }
}
<commit_msg>Simplify and refactor<commit_after>use super::*;

impl Editor {
    /// Goto a given position
    #[inline]
    pub fn goto(&mut self, (x, y): (usize, usize)) {
        self.cursor_mut().x = x;
        self.cursor_mut().y = y;
    }

    /// Get the position of the next char
    #[inline]
    pub fn next_pos(&self) -> (usize, usize) {
        // TODO: Add numerals
        if self.x() == self.text[self.y()].len() {
            if self.y() < self.text.len() - 1 {
                (0, self.y() + 1)
            } else {
                (self.x(), self.y())
            }
        } else {
            (self.x() + 1, self.y())
        }
    }

    /// Get the position of previous char
    #[inline]
    pub fn previous_pos(&self) -> (usize, usize) {
        if self.x() == 0 {
            if self.y() > 0 {
                (self.text[self.y() - 1].len(), self.y() - 1)
            } else {
                (self.x(), self.y())
            }
        } else {
            (self.x() - 1, self.y())
        }
    }

    /// Goto the next char
    #[inline]
    pub fn goto_next(&mut self) {
        let p = self.next_pos();
        self.goto(p);
    }
    /// Goto the previous char
    #[inline]
    pub fn goto_previous(&mut self) {
        let p = self.previous_pos();
        self.goto(p);
    }

    /// Get the position of the right char
    #[inline]
    pub fn right_pos(&self, n: usize) -> (usize, usize) {
        (self.x() + n, self.y())
    }
    /// Goto the right char
    #[inline]
    pub fn goto_right(&mut self, n: usize) {
        self.cursor_mut().x = self.right_pos(n).0;
    }

    /// Get the position of the left char
    #[inline]
    pub fn left_pos(&self, n: usize) -> (usize, usize) {
        if n <= self.x() {
            (self.x() - n, self.y())
        } else {
            (0, self.y())
        }
    }
    /// Goto the left char
    #[inline]
    pub fn goto_left(&mut self, n: usize) {
        self.cursor_mut().x = self.left_pos(n).0;
    }

    /// Get the position of the char above the cursor
    #[inline]
    pub fn up_pos(&self, n: usize) -> (usize, usize) {
        if n <= self.y() {
            (self.cursor().x, self.y() - n)
        } else {
            (self.cursor().x, 0)
        }
    }
    /// Go a char up
    #[inline]
    pub fn goto_up(&mut self, n: usize) {
        let p = self.up_pos(n);
        self.goto(p);
    }

    /// Get the position under the char
    #[inline]
    pub fn down_pos(&self, n: usize) -> (usize, usize) {
        (self.cursor().x, self.y() + n)
    }

    /// Go down
    #[inline]
    pub fn goto_down(&mut self, n: usize) {
        let p = self.down_pos(n);
        self.goto(p);
    }

    /// Get the position of the end of the line
    #[inline]
    pub fn ln_end_pos(&self) -> (usize, usize) {
        (self.text[self.y()].len(), self.y())
    }

    /// Goto line end
    #[inline]
    pub fn goto_ln_end(&mut self) {
        let p = self.ln_end_pos();
        self.goto(p);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::io::Write;
use std::fs::File;
use std::path::{Path, PathBuf};

use ops::{Context, Unit};
use util::{CargoResult, internal};
use ops::cargo_rustc::fingerprint;

fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResult<String> {
    let path = path.as_ref();
    let relpath = match basedir {
        None => path,
        Some(base) => match path.strip_prefix(base) {
            Ok(relpath) => relpath,
            _ => path,
        }
    };
    relpath.to_str().ok_or(internal("path not utf-8")).map(|f| f.replace(" ", "\\ "))
}

fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet<PathBuf>, context: &mut Context<'a, 'b>,
    unit: &Unit<'a>, visited: &mut HashSet<Unit<'a>>) -> CargoResult<()>
{
    if visited.contains(unit) {
        return Ok(());
    }
    visited.insert(unit.clone());

    let dep_info_loc = fingerprint::dep_info_loc(context, unit);
    if let Some(paths) = fingerprint::parse_dep_info(&dep_info_loc)? {
        for path in paths {
            deps.insert(path);
        }
    }

    // recursively traverse all transitive dependencies
    for dep_unit in &context.dep_targets(unit)? {
        let source_id = dep_unit.pkg.package_id().source_id();
        if source_id.is_path() {
            add_deps_for_unit(deps, context, dep_unit, visited)?;
        }
    }
    Ok(())
}

pub fn output_depinfo<'a, 'b>(context: &mut Context<'a, 'b>, unit: &Unit<'a>) -> CargoResult<()> {
    let mut deps = HashSet::new();
    let mut visited = HashSet::new();
    add_deps_for_unit(&mut deps, context, unit, &mut visited)?;
    let basedir = None; // TODO
    for (_filename, link_dst, _linkable) in context.target_filenames(unit)? {
        if let Some(link_dst) = link_dst {
            let output_path = link_dst.with_extension("d");
            let target_fn = render_filename(link_dst, basedir)?;
            let mut outfile = File::create(output_path)?;
            write!(outfile, "{}:", target_fn)?;
            for dep in &deps {
                write!(outfile, " {}", render_filename(dep, basedir)?)?;
            }
            writeln!(outfile, "")?;
        }
    }
    Ok(())
}
<commit_msg>Buffer file writing for dep-info<commit_after>use std::collections::HashSet;
use std::io::{Write, BufWriter};
use std::fs::File;
use std::path::{Path, PathBuf};

use ops::{Context, Unit};
use util::{CargoResult, internal};
use ops::cargo_rustc::fingerprint;

fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResult<String> {
    let path = path.as_ref();
    let relpath = match basedir {
        None => path,
        Some(base) => match path.strip_prefix(base) {
            Ok(relpath) => relpath,
            _ => path,
        }
    };
    relpath.to_str().ok_or(internal("path not utf-8")).map(|f| f.replace(" ", "\\ "))
}

fn add_deps_for_unit<'a, 'b>(deps: &mut HashSet<PathBuf>, context: &mut Context<'a, 'b>,
    unit: &Unit<'a>, visited: &mut HashSet<Unit<'a>>) -> CargoResult<()>
{
    if visited.contains(unit) {
        return Ok(());
    }
    visited.insert(unit.clone());

    let dep_info_loc = fingerprint::dep_info_loc(context, unit);
    if let Some(paths) = fingerprint::parse_dep_info(&dep_info_loc)? {
        for path in paths {
            deps.insert(path);
        }
    }

    // recursively traverse all transitive dependencies
    for dep_unit in &context.dep_targets(unit)? {
        let source_id = dep_unit.pkg.package_id().source_id();
        if source_id.is_path() {
            add_deps_for_unit(deps, context, dep_unit, visited)?;
        }
    }
    Ok(())
}

pub fn output_depinfo<'a, 'b>(context: &mut Context<'a, 'b>, unit: &Unit<'a>) -> CargoResult<()> {
    let mut deps = HashSet::new();
    let mut visited = HashSet::new();
    add_deps_for_unit(&mut deps, context, unit, &mut visited)?;
    let basedir = None; // TODO
    for (_filename, link_dst, _linkable) in context.target_filenames(unit)? {
        if let Some(link_dst) = link_dst {
            let output_path = link_dst.with_extension("d");
            let target_fn = render_filename(link_dst, basedir)?;
            let mut outfile = BufWriter::new(File::create(output_path)?);
            write!(outfile, "{}:", target_fn)?;
            for dep in &deps {
                write!(outfile, " {}", render_filename(dep, basedir)?)?;
            }
            writeln!(outfile, "")?;
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate reqwest;
extern crate serde;
extern crate serde_json;

use std::io::Read;
use std::num::ParseFloatError;

use irc::client::prelude::*;

use self::reqwest::Client;
use self::reqwest::header::Connection;
use self::serde_json::Value;

use plugin::*;

use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::ResultExt;

#[derive(PluginName, Default, Debug)]
pub struct Currency;

struct ConvertionRequest<'a> {
    value: f64,
    source: &'a str,
    target: &'a str,
}

impl<'a> ConvertionRequest<'a> {
    fn send(&self) -> Option<f64> {
        let response = Client::new()
            .get("https://api.fixer.io/latest")
            .form(&[("base", self.source)])
            .header(Connection::close())
            .send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                response.read_to_string(&mut body).ok()?;

                let convertion_rates: Result<Value, _> = serde_json::from_str(&body);
                match convertion_rates {
                    Ok(convertion_rates) => {
                        let rates: &Value = convertion_rates.get("rates")?;
                        let target_rate: &Value = rates.get(self.target.to_uppercase())?;
                        Some(self.value * target_rate.as_f64()?)
                    }
                    Err(_) => None,
                }
            }
            Err(_) => None,
        }
    }
}

impl Currency {
    pub fn new() -> Currency {
        Currency {}
    }

    fn eval_command<'a>(
        &self,
        tokens: &'a [String],
    ) -> Result<ConvertionRequest<'a>, ParseFloatError> {
        Ok(ConvertionRequest {
            value: tokens[0].parse()?,
            source: &tokens[1],
            target: &tokens[2],
        })
    }

    fn convert(&self, command: &mut PluginCommand) -> Result<String, &str> {
        if command.tokens.len() < 3 {
            return Err(self.invalid_command());
        }

        let request = match self.eval_command(&command.tokens) {
            Ok(request) => request,
            Err(_) => {
                return Err(self.invalid_command());
            }
        };

        match request.send() {
            Some(response) => {
                let response = format!(
                    "{} {} => {:.4} {}",
                    request.value,
                    request.source.to_lowercase(),
                    response / 1.00000000,
                    request.target.to_lowercase()
                );

                Ok(response)
            }
            None => Err("An error occured during the conversion of the given currency"),
        }
    }

    fn help(&self) -> &str {
        "usage: currency value from_currency to_currency\r\n\
         example: {0} currency 1.5 eur usd\r\n\
         available currencies: AUD, BGN, BRL, CAD, \
         CHF, CNY, CZK, DKK, GBP, HKD, HRK, HUF, \
         IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \
         NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \
         TRY, USD, ZAR"
    }

    fn invalid_command(&self) -> &str {
        "Incorrect Command. \
         Send \"currency help\" for help."
    }
}

impl Plugin for Currency {
    fn execute(&self, _: &IrcClient, _: &Message) -> ExecutionStatus {
        ExecutionStatus::Done
    }

    fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
        panic!("Currency does not implement the execute function!")
    }

    fn command(&self, client: &IrcClient, mut command: PluginCommand) -> Result<(), FrippyError> {
        if command.tokens.is_empty() {
            return Ok(client
                .send_notice(&command.source, &self.invalid_command())
                .context(FrippyErrorKind::Connection)?);
        }

        match command.tokens[0].as_ref() {
            "help" => Ok(client
                .send_notice(&command.source, self.help())
                .context(FrippyErrorKind::Connection)?),
            _ => match self.convert(&mut command) {
                Ok(msg) => Ok(client
                    .send_privmsg(&command.target, &msg)
                    .context(FrippyErrorKind::Connection)?),
                Err(msg) => Ok(client
                    .send_notice(&command.source, &msg)
                    .context(FrippyErrorKind::Connection)?),
            },
        }
    }

    fn evaluate(&self, _: &IrcClient, mut command: PluginCommand) -> Result<String, String> {
        if command.tokens.is_empty() {
            return Err(self.invalid_command().to_owned());
        }

        match command.tokens[0].as_ref() {
            "help" => Ok(self.help().to_owned()),
            _ => self.convert(&mut command).map_err(|e| e.to_owned()),
        }
    }
}
<commit_msg>Currency: Fix help message<commit_after>extern crate reqwest;
extern crate serde;
extern crate serde_json;

use std::io::Read;
use std::num::ParseFloatError;

use irc::client::prelude::*;

use self::reqwest::Client;
use self::reqwest::header::Connection;
use self::serde_json::Value;

use plugin::*;

use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::ResultExt;

#[derive(PluginName, Default, Debug)]
pub struct Currency;

struct ConvertionRequest<'a> {
    value: f64,
    source: &'a str,
    target: &'a str,
}

impl<'a> ConvertionRequest<'a> {
    fn send(&self) -> Option<f64> {
        let response = Client::new()
            .get("https://api.fixer.io/latest")
            .form(&[("base", self.source)])
            .header(Connection::close())
            .send();

        match response {
            Ok(mut response) => {
                let mut body = String::new();
                response.read_to_string(&mut body).ok()?;

                let convertion_rates: Result<Value, _> = serde_json::from_str(&body);
                match convertion_rates {
                    Ok(convertion_rates) => {
                        let rates: &Value = convertion_rates.get("rates")?;
                        let target_rate: &Value = rates.get(self.target.to_uppercase())?;
                        Some(self.value * target_rate.as_f64()?)
                    }
                    Err(_) => None,
                }
            }
            Err(_) => None,
        }
    }
}

impl Currency {
    pub fn new() -> Currency {
        Currency {}
    }

    fn eval_command<'a>(
        &self,
        tokens: &'a [String],
    ) -> Result<ConvertionRequest<'a>, ParseFloatError> {
        Ok(ConvertionRequest {
            value: tokens[0].parse()?,
            source: &tokens[1],
            target: &tokens[2],
        })
    }

    fn convert(&self, command: &mut PluginCommand) -> Result<String, &str> {
        if command.tokens.len() < 3 {
            return Err(self.invalid_command());
        }

        let request = match self.eval_command(&command.tokens) {
            Ok(request) => request,
            Err(_) => {
                return Err(self.invalid_command());
            }
        };

        match request.send() {
            Some(response) => {
                let response = format!(
                    "{} {} => {:.4} {}",
                    request.value,
                    request.source.to_lowercase(),
                    response / 1.00000000,
                    request.target.to_lowercase()
                );

                Ok(response)
            }
            None => Err("An error occured during the conversion of the given currency"),
        }
    }

    fn help(&self) -> &str {
        "usage: currency value from_currency to_currency\r\n\
         example: currency 1.5 eur usd\r\n\
         available currencies: AUD, BGN, BRL, CAD, \
         CHF, CNY, CZK, DKK, GBP, HKD, HRK, HUF, \
         IDR, ILS, INR, JPY, KRW, MXN, MYR, NOK, \
         NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, \
         TRY, USD, ZAR"
    }

    fn invalid_command(&self) -> &str {
        "Incorrect Command. \
         Send \"currency help\" for help."
    }
}

impl Plugin for Currency {
    fn execute(&self, _: &IrcClient, _: &Message) -> ExecutionStatus {
        ExecutionStatus::Done
    }

    fn execute_threaded(&self, _: &IrcClient, _: &Message) -> Result<(), FrippyError> {
        panic!("Currency does not implement the execute function!")
    }

    fn command(&self, client: &IrcClient, mut command: PluginCommand) -> Result<(), FrippyError> {
        if command.tokens.is_empty() {
            return Ok(client
                .send_notice(&command.source, &self.invalid_command())
                .context(FrippyErrorKind::Connection)?);
        }

        match command.tokens[0].as_ref() {
            "help" => Ok(client
                .send_notice(&command.source, self.help())
                .context(FrippyErrorKind::Connection)?),
            _ => match self.convert(&mut command) {
                Ok(msg) => Ok(client
                    .send_privmsg(&command.target, &msg)
                    .context(FrippyErrorKind::Connection)?),
                Err(msg) => Ok(client
                    .send_notice(&command.source, &msg)
                    .context(FrippyErrorKind::Connection)?),
            },
        }
    }

    fn evaluate(&self, _: &IrcClient, mut command: PluginCommand) -> Result<String, String> {
        if command.tokens.is_empty() {
            return Err(self.invalid_command().to_owned());
        }

        match command.tokens[0].as_ref() {
            "help" => Ok(self.help().to_owned()),
            _ => self.convert(&mut command).map_err(|e| e.to_owned()),
        }
    }
}
<|endoftext|>


<commit_before>use self::rsvg_internals::surface_utils::{
    iterators::Pixels,
    shared_surface::{SharedImageSurface, SurfaceType},
    ImageSurfaceDataExt, Pixel,
};
use self::rsvg_internals::{IRect, RenderingError};
use rsvg_internals;

pub enum BufferDiff {
    DifferentSizes,
    Diff(Diff),
}

pub struct Diff {
    pub num_pixels_changed: usize,
    pub max_diff: u8,
    pub surface: SharedImageSurface,
}

#[inline]
fn pixel_max(p: &Pixel) -> u8 {
    p.r.max(p.g).max(p.b).max(p.a)
}

#[inline]
fn emphasize(p: &Pixel) -> Pixel {
    let mut r = p.r as u32;
    let mut g = p.g as u32;
    let mut b = p.b as u32;
    let mut a = p.a as u32;

    // emphasize
    r = r * 4;
    g = g * 4;
    b = b * 4;
    a = a * 4;

    // make sure they are visible
    if r > 0 {
        r += 128;
    }

    if g > 0 {
        g += 128;
    }

    if b > 0 {
        b += 128;
    }

    if a > 0 {
        a += 128;
    }

    let r = r.min(255) as u8;
    let g = g.min(255) as u8;
    let b = b.min(255) as u8;
    let a = a.min(255) as u8;

    Pixel { r, g, b, a }
}

pub fn compare_surfaces(
    surf_a: &SharedImageSurface,
    surf_b: &SharedImageSurface,
) -> Result<BufferDiff, RenderingError> {
    let a_width = surf_a.width();
    let a_height = surf_a.height();

    let b_width = surf_b.width();
    let b_height = surf_b.height();

    if a_width != b_width || a_height != b_height {
        return Ok(BufferDiff::DifferentSizes);
    }

    let mut surf_diff = cairo::ImageSurface::create(cairo::Format::ARgb32, a_width, a_height)?;
    let diff_stride = surf_diff.get_stride() as usize;

    let mut num_pixels_changed = 0;
    let mut max_diff = 0;

    {
        let mut diff_data = surf_diff.get_data().unwrap();

        for ((xa, ya, pixel_a), (_, _, pixel_b)) in Pixels::new(surf_a).zip(Pixels::new(surf_b)) {
            if pixel_a != pixel_b {
                num_pixels_changed += 1;

                let pixel_diff = pixel_a.diff(&pixel_b);

                let pixel_max_diff = pixel_max(&pixel_diff);

                max_diff = max_diff.max(pixel_max_diff);

                let mut pixel_diff = emphasize(&pixel_diff);

                if pixel_diff.r == 0 && pixel_diff.g == 0 && pixel_diff.b == 0 {
                    // alpha only difference; convert alpha to gray

                    pixel_diff.r = pixel_diff.a;
                    pixel_diff.g = pixel_diff.a;
                    pixel_diff.b = pixel_diff.a;
                }

                diff_data.set_pixel(diff_stride, pixel_diff, xa, ya);
            } else {
                let black = Pixel {
                    r: 0,
                    g: 0,
                    b: 0,
                    a: 0,
                };
                diff_data.set_pixel(diff_stride, black, xa, ya);
            }
        }
    }

    let surface = SharedImageSurface::wrap(surf_diff, SurfaceType::SRgb)?;

    Ok(BufferDiff::Diff(Diff {
        num_pixels_changed,
        max_diff,
        surface,
    }))
}
<commit_msg>compare_surfaces: set the alpha of the diff always to opaque<commit_after>use self::rsvg_internals::surface_utils::{
    iterators::Pixels,
    shared_surface::{SharedImageSurface, SurfaceType},
    ImageSurfaceDataExt, Pixel,
};
use self::rsvg_internals::{IRect, RenderingError};
use rsvg_internals;

pub enum BufferDiff {
    DifferentSizes,
    Diff(Diff),
}

pub struct Diff {
    pub num_pixels_changed: usize,
    pub max_diff: u8,
    pub surface: SharedImageSurface,
}

#[inline]
fn pixel_max(p: &Pixel) -> u8 {
    p.r.max(p.g).max(p.b).max(p.a)
}

#[inline]
fn emphasize(p: &Pixel) -> Pixel {
    let mut r = p.r as u32;
    let mut g = p.g as u32;
    let mut b = p.b as u32;
    let mut a = p.a as u32;

    // emphasize
    r = r * 4;
    g = g * 4;
    b = b * 4;
    a = a * 4;

    // make sure they are visible
    if r > 0 {
        r += 128;
    }

    if g > 0 {
        g += 128;
    }

    if b > 0 {
        b += 128;
    }

    if a > 0 {
        a += 128;
    }

    let r = r.min(255) as u8;
    let g = g.min(255) as u8;
    let b = b.min(255) as u8;
    let a = a.min(255) as u8;

    Pixel { r, g, b, a }
}

pub fn compare_surfaces(
    surf_a: &SharedImageSurface,
    surf_b: &SharedImageSurface,
) -> Result<BufferDiff, RenderingError> {
    let a_width = surf_a.width();
    let a_height = surf_a.height();

    let b_width = surf_b.width();
    let b_height = surf_b.height();

    if a_width != b_width || a_height != b_height {
        return Ok(BufferDiff::DifferentSizes);
    }

    let mut surf_diff = cairo::ImageSurface::create(cairo::Format::ARgb32, a_width, a_height)?;
    let diff_stride = surf_diff.get_stride() as usize;

    let mut num_pixels_changed = 0;
    let mut max_diff = 0;

    {
        let mut diff_data = surf_diff.get_data().unwrap();

        for ((xa, ya, pixel_a), (_, _, pixel_b)) in Pixels::new(surf_a).zip(Pixels::new(surf_b)) {
            if pixel_a != pixel_b {
                num_pixels_changed += 1;

                let pixel_diff = pixel_a.diff(&pixel_b);

                let pixel_max_diff = pixel_max(&pixel_diff);

                max_diff = max_diff.max(pixel_max_diff);

                let mut pixel_diff = emphasize(&pixel_diff);

                if pixel_diff.r == 0 && pixel_diff.g == 0 && pixel_diff.b == 0 {
                    // alpha only difference; convert alpha to gray

                    pixel_diff.r = pixel_diff.a;
                    pixel_diff.g = pixel_diff.a;
                    pixel_diff.b = pixel_diff.a;
                }

                pixel_diff.a = 255;

                diff_data.set_pixel(diff_stride, pixel_diff, xa, ya);
            } else {
                let black = Pixel {
                    r: 0,
                    g: 0,
                    b: 0,
                    a: 255,
                };
                diff_data.set_pixel(diff_stride, black, xa, ya);
            }
        }
    }

    let surface = SharedImageSurface::wrap(surf_diff, SurfaceType::SRgb)?;

    Ok(BufferDiff::Diff(Diff {
        num_pixels_changed,
        max_diff,
        surface,
    }))
}
<|endoftext|>


<commit_before>//! This module contains functionality for decompression.

#[cfg(feature = "with-alloc")]
use crate::alloc::{boxed::Box, vec, vec::Vec};
use ::core::usize;

pub mod core;
mod output_buffer;
pub mod stream;
use self::core::*;

const TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS: i32 = -4;
const TINFL_STATUS_BAD_PARAM: i32 = -3;
const TINFL_STATUS_ADLER32_MISMATCH: i32 = -2;
const TINFL_STATUS_FAILED: i32 = -1;
const TINFL_STATUS_DONE: i32 = 0;
const TINFL_STATUS_NEEDS_MORE_INPUT: i32 = 1;
const TINFL_STATUS_HAS_MORE_OUTPUT: i32 = 2;

/// Return status codes.
#[repr(i8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TINFLStatus {
    /// More input data was expected, but the caller indicated that there was no more data, so the
    /// input stream is likely truncated.
    ///
    /// This can't happen if you have provided the
    /// [`TINFL_FLAG_HAS_MORE_INPUT`][core::inflate_flags::TINFL_FLAG_HAS_MORE_INPUT] flag to the
    /// decompression.  By setting that flag, you indicate more input exists but is not provided,
    /// and so reaching the end of the input data without finding the end of the compressed stream
    /// would instead return a [`NeedsMoreInput`][Self::NeedsMoreInput] status.
    FailedCannotMakeProgress = TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS as i8,

    /// The output buffer is an invalid size; consider the `flags` parameter.
    BadParam = TINFL_STATUS_BAD_PARAM as i8,

    /// The decompression went fine, but the adler32 checksum did not match the one
    /// provided in the header.
    Adler32Mismatch = TINFL_STATUS_ADLER32_MISMATCH as i8,

    /// Failed to decompress due to invalid data.
    Failed = TINFL_STATUS_FAILED as i8,

    /// Finished decompression without issues.
    ///
    /// This indicates the end of the compressed stream has been reached.
    Done = TINFL_STATUS_DONE as i8,

    /// The decompressor needs more input data to continue decompressing.
    ///
    /// This occurs when there's no more consumable input, but the end of the stream hasn't been
    /// reached, and you have supplied the
    /// [`TINFL_FLAG_HAS_MORE_INPUT`][core::inflate_flags::TINFL_FLAG_HAS_MORE_INPUT] flag to the
    /// decompressor.  Had you not supplied that flag (which would mean you were asserting that you
    /// believed all the data was available) you would have gotten a
    /// [`FailedCannotMakeProcess`][Self::FailedCannotMakeProgress] instead.
    NeedsMoreInput = TINFL_STATUS_NEEDS_MORE_INPUT as i8,

    /// There is still pending data that didn't fit in the output buffer.
    HasMoreOutput = TINFL_STATUS_HAS_MORE_OUTPUT as i8,
}

impl TINFLStatus {
    pub fn from_i32(value: i32) -> Option<TINFLStatus> {
        use self::TINFLStatus::*;
        match value {
            TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS => Some(FailedCannotMakeProgress),
            TINFL_STATUS_BAD_PARAM => Some(BadParam),
            TINFL_STATUS_ADLER32_MISMATCH => Some(Adler32Mismatch),
            TINFL_STATUS_FAILED => Some(Failed),
            TINFL_STATUS_DONE => Some(Done),
            TINFL_STATUS_NEEDS_MORE_INPUT => Some(NeedsMoreInput),
            TINFL_STATUS_HAS_MORE_OUTPUT => Some(HasMoreOutput),
            _ => None,
        }
    }
}

/// Struct return when decompress_to_vec functions fail.
#[cfg(feature = "with-alloc")]
#[derive(Debug)]
pub struct DecompressError {
    /// Decompressor status on failure. See [TINFLStatus] for details.
    pub status: TINFLStatus,
    /// The currently decompressed data if any.
    pub output: Vec<u8>,
}

fn decompress_error(status: TINFLStatus, output: Vec<u8>) -> Result<Vec<u8>, DecompressError> {
    Err(DecompressError { status, output })
}

/// Decompress the deflate-encoded data in `input` to a vector.
///
/// NOTE: This function will not bound the output, so if the output is large enough it can result in an out of memory error.
/// It is therefore suggested to not use this for anything other than test programs, use the functions with a specified limit, or
/// ideally streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead.
///
/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] containing the status and so far decompressed data if any on failure.
#[inline]
#[cfg(feature = "with-alloc")]
pub fn decompress_to_vec(input: &[u8]) -> Result<Vec<u8>, DecompressError> {
    decompress_to_vec_inner(input, 0, usize::max_value())
}

/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector.
///
/// NOTE: This function will not bound the output, so if the output is large enough it can result in an out of memory error.
/// It is therefore suggested to not use this for anything other than test programs, use the functions with a specified limit, or
/// ideally streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead.
///
/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] containing the status and so far decompressed data if any on failure.
#[inline]
#[cfg(feature = "with-alloc")]
pub fn decompress_to_vec_zlib(input: &[u8]) -> Result<Vec<u8>, DecompressError> {
    decompress_to_vec_inner(
        input,
        inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER,
        usize::max_value(),
    )
}

/// Decompress the deflate-encoded data in `input` to a vector.
///
/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size,
/// the error [struct][DecompressError] will contain the status [`TINFLStatus::HasMoreOutput`] and the data that was decompressed on failure.
///
/// As this function tries to decompress everything in one go, it's not ideal for general use outside of tests or where the output size is expected to be small.
/// It is suggested to use streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead.
///
/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] on failure.
#[inline]
#[cfg(feature = "with-alloc")]
pub fn decompress_to_vec_with_limit(
    input: &[u8],
    max_size: usize,
) -> Result<Vec<u8>, DecompressError> {
    decompress_to_vec_inner(input, 0, max_size)
}

/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector.
/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size,
/// the error [struct][DecompressError] will contain the status [`TINFLStatus::HasMoreOutput`] and the data that was decompressed on failure.
///
/// As this function tries to decompress everything in one go, it's not ideal for general use outside of tests or where the output size is expected to be small.
/// It is suggested to use streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead.
///
/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] on failure.
#[inline]
#[cfg(feature = "with-alloc")]
pub fn decompress_to_vec_zlib_with_limit(
    input: &[u8],
    max_size: usize,
) -> Result<Vec<u8>, DecompressError> {
    decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, max_size)
}

/// Backend of various to-[`Vec`] decompressions.
///
/// Returns [`Vec`] of decompressed data on success and the [error struct][DecompressError] with details on failure.
#[cfg(feature = "with-alloc")]
fn decompress_to_vec_inner(
    input: &[u8],
    flags: u32,
    max_output_size: usize,
) -> Result<Vec<u8>, DecompressError> {
    let flags = flags | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
    let mut ret: Vec<u8> = vec![0; input.len().saturating_mul(2).min(max_output_size)];

    let mut decomp = Box::<DecompressorOxide>::default();

    let mut in_pos = 0;
    let mut out_pos = 0;
    loop {
        // Wrap the whole output slice so we know we have enough of the
        // decompressed data for matches.
        let (status, in_consumed, out_consumed) =
            decompress(&mut decomp, &input[in_pos..], &mut ret, out_pos, flags);
        in_pos += in_consumed;
        out_pos += out_consumed;

        match status {
            TINFLStatus::Done => {
                ret.truncate(out_pos);
                return Ok(ret);
            }

            TINFLStatus::HasMoreOutput => {
                // if the buffer has already reached the size limit, return an error
                if ret.len() >= max_output_size {
                    return decompress_error(TINFLStatus::HasMoreOutput, ret);
                }
                // calculate the new length, capped at `max_output_size`
                let new_len = ret.len().saturating_mul(2).min(max_output_size);
                ret.resize(new_len, 0);
            }

            _ => return decompress_error(status, ret),
        }
    }
}

/// Decompress one or more source slices from an iterator into the output slice.
///
/// * On success, returns the number of bytes that were written.
/// * On failure, returns the failure status code.
///
/// This will fail if the output buffer is not large enough, but in that case
/// the output buffer will still contain the partial decompression.
///
/// * `out` the output buffer.
/// * `it` the iterator of input slices.
/// * `zlib_header` if the first slice out of the iterator is expected to have a
///   Zlib header. Otherwise the slices are assumed to be the deflate data only.
/// * `ignore_adler32` if the adler32 checksum should be calculated or not.
pub fn decompress_slice_iter_to_slice<'out, 'inp>(
    out: &'out mut [u8],
    it: impl Iterator<Item = &'inp [u8]>,
    zlib_header: bool,
    ignore_adler32: bool,
) -> Result<usize, TINFLStatus> {
    use self::core::inflate_flags::*;

    let mut it = it.peekable();
    let r = &mut DecompressorOxide::new();
    let mut out_pos = 0;
    while let Some(in_buf) = it.next() {
        let has_more = it.peek().is_some();
        let flags = {
            let mut f = TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
            if zlib_header {
                f |= TINFL_FLAG_PARSE_ZLIB_HEADER;
            }
            if ignore_adler32 {
                f |= TINFL_FLAG_IGNORE_ADLER32;
            }
            if has_more {
                f |= TINFL_FLAG_HAS_MORE_INPUT;
            }
            f
        };
        let (status, _input_read, bytes_written) = decompress(r, in_buf, out, out_pos, flags);
        out_pos += bytes_written;
        match status {
            TINFLStatus::NeedsMoreInput => continue,
            TINFLStatus::Done => return Ok(out_pos),
            e => return Err(e),
        }
    }
    // If we ran out of source slices without getting a `Done` from the
    // decompression we can call it a failure.
    Err(TINFLStatus::FailedCannotMakeProgress)
}

#[cfg(test)]
mod test {
    use super::{
        decompress_slice_iter_to_slice, decompress_to_vec_zlib, decompress_to_vec_zlib_with_limit,
        DecompressError, TINFLStatus,
    };
    const ENCODED: [u8; 20] = [
        120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19,
    ];

    #[test]
    fn decompress_vec() {
        let res = decompress_to_vec_zlib(&ENCODED[..]).unwrap();
        assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]);
    }

    #[test]
    fn decompress_vec_with_high_limit() {
        let res = decompress_to_vec_zlib_with_limit(&ENCODED[..], 100_000).unwrap();
        assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]);
    }

    #[test]
    fn fail_to_decompress_with_limit() {
        let res = decompress_to_vec_zlib_with_limit(&ENCODED[..], 8);
        match res {
            Err(DecompressError {
                status: TINFLStatus::HasMoreOutput,
                ..
            }) => (), // expected result
            _ => panic!("Decompression output size limit was not enforced"),
        }
    }

    #[test]
    fn test_decompress_slice_iter_to_slice() {
        // one slice
        let mut out = [0_u8; 12_usize];
        let r =
            decompress_slice_iter_to_slice(&mut out, Some(&ENCODED[..]).into_iter(), true, false);
        assert_eq!(r, Ok(12));
        assert_eq!(&out[..12], &b"Hello, zlib!"[..]);

        // some chunks at a time
        for chunk_size in 1..13 {
            // Note: because of https://github.com/Frommi/miniz_oxide/issues/110 our
            // out buffer needs to have +1 byte available when the chunk size cuts
            // the adler32 data off from the last actual data.
            let mut out = [0_u8; 12_usize + 1];
            let r =
                decompress_slice_iter_to_slice(&mut out, ENCODED.chunks(chunk_size), true, false);
            assert_eq!(r, Ok(12));
            assert_eq!(&out[..12], &b"Hello, zlib!"[..]);
        }

        // output buffer too small
        let mut out = [0_u8; 3_usize];
        let r = decompress_slice_iter_to_slice(&mut out, ENCODED.chunks(7), true, false);
        assert!(r.is_err());
    }
}
<commit_msg>fix(inflate): Make building with --no-default-features actually work<commit_after>//! This module contains functionality for decompression.

#[cfg(feature = "with-alloc")]
use crate::alloc::{boxed::Box, vec, vec::Vec};
use ::core::usize;

pub mod core;
mod output_buffer;
pub mod stream;
use self::core::*;

const TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS: i32 = -4;
const TINFL_STATUS_BAD_PARAM: i32 = -3;
const TINFL_STATUS_ADLER32_MISMATCH: i32 = -2;
const TINFL_STATUS_FAILED: i32 = -1;
const TINFL_STATUS_DONE: i32 = 0;
const TINFL_STATUS_NEEDS_MORE_INPUT: i32 = 1;
const TINFL_STATUS_HAS_MORE_OUTPUT: i32 = 2;

/// Return status codes.
#[repr(i8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TINFLStatus {
    /// More input data was expected, but the caller indicated that there was no more data, so the
    /// input stream is likely truncated.
    ///
    /// This can't happen if you have provided the
    /// [`TINFL_FLAG_HAS_MORE_INPUT`][core::inflate_flags::TINFL_FLAG_HAS_MORE_INPUT] flag to the
    /// decompression.  By setting that flag, you indicate more input exists but is not provided,
    /// and so reaching the end of the input data without finding the end of the compressed stream
    /// would instead return a [`NeedsMoreInput`][Self::NeedsMoreInput] status.
    FailedCannotMakeProgress = TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS as i8,

    /// The output buffer is an invalid size; consider the `flags` parameter.
    BadParam = TINFL_STATUS_BAD_PARAM as i8,

    /// The decompression went fine, but the adler32 checksum did not match the one
    /// provided in the header.
    Adler32Mismatch = TINFL_STATUS_ADLER32_MISMATCH as i8,

    /// Failed to decompress due to invalid data.
    Failed = TINFL_STATUS_FAILED as i8,

    /// Finished decompression without issues.
    ///
    /// This indicates the end of the compressed stream has been reached.
    Done = TINFL_STATUS_DONE as i8,

    /// The decompressor needs more input data to continue decompressing.
    ///
    /// This occurs when there's no more consumable input, but the end of the stream hasn't been
    /// reached, and you have supplied the
    /// [`TINFL_FLAG_HAS_MORE_INPUT`][core::inflate_flags::TINFL_FLAG_HAS_MORE_INPUT] flag to the
    /// decompressor.  Had you not supplied that flag (which would mean you were asserting that you
    /// believed all the data was available) you would have gotten a
    /// [`FailedCannotMakeProcess`][Self::FailedCannotMakeProgress] instead.
    NeedsMoreInput = TINFL_STATUS_NEEDS_MORE_INPUT as i8,

    /// There is still pending data that didn't fit in the output buffer.
    HasMoreOutput = TINFL_STATUS_HAS_MORE_OUTPUT as i8,
}

impl TINFLStatus {
    pub fn from_i32(value: i32) -> Option<TINFLStatus> {
        use self::TINFLStatus::*;
        match value {
            TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS => Some(FailedCannotMakeProgress),
            TINFL_STATUS_BAD_PARAM => Some(BadParam),
            TINFL_STATUS_ADLER32_MISMATCH => Some(Adler32Mismatch),
            TINFL_STATUS_FAILED => Some(Failed),
            TINFL_STATUS_DONE => Some(Done),
            TINFL_STATUS_NEEDS_MORE_INPUT => Some(NeedsMoreInput),
            TINFL_STATUS_HAS_MORE_OUTPUT => Some(HasMoreOutput),
            _ => None,
        }
    }
}

/// Struct return when decompress_to_vec functions fail.
#[cfg(feature = "with-alloc")]
#[derive(Debug)]
pub struct DecompressError {
    /// Decompressor status on failure. See [TINFLStatus] for details.
    pub status: TINFLStatus,
    /// The currently decompressed data if any.
    pub output: Vec<u8>,
}

#[cfg(feature = "with-alloc")]
fn decompress_error(status: TINFLStatus, output: Vec<u8>) -> Result<Vec<u8>, DecompressError> {
    Err(DecompressError { status, output })
}

/// Decompress the deflate-encoded data in `input` to a vector.
///
/// NOTE: This function will not bound the output, so if the output is large enough it can result in an out of memory error.
/// It is therefore suggested to not use this for anything other than test programs, use the functions with a specified limit, or
/// ideally streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead.
///
/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] containing the status and so far decompressed data if any on failure.
#[inline]
#[cfg(feature = "with-alloc")]
pub fn decompress_to_vec(input: &[u8]) -> Result<Vec<u8>, DecompressError> {
    decompress_to_vec_inner(input, 0, usize::max_value())
}

/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector.
///
/// NOTE: This function will not bound the output, so if the output is large enough it can result in an out of memory error.
/// It is therefore suggested to not use this for anything other than test programs, use the functions with a specified limit, or
/// ideally streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead.
///
/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] containing the status and so far decompressed data if any on failure.
#[inline]
#[cfg(feature = "with-alloc")]
pub fn decompress_to_vec_zlib(input: &[u8]) -> Result<Vec<u8>, DecompressError> {
    decompress_to_vec_inner(
        input,
        inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER,
        usize::max_value(),
    )
}

/// Decompress the deflate-encoded data in `input` to a vector.
///
/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size,
/// the error [struct][DecompressError] will contain the status [`TINFLStatus::HasMoreOutput`] and the data that was decompressed on failure.
///
/// As this function tries to decompress everything in one go, it's not ideal for general use outside of tests or where the output size is expected to be small.
/// It is suggested to use streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead.
///
/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] on failure.
#[inline]
#[cfg(feature = "with-alloc")]
pub fn decompress_to_vec_with_limit(
    input: &[u8],
    max_size: usize,
) -> Result<Vec<u8>, DecompressError> {
    decompress_to_vec_inner(input, 0, max_size)
}

/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector.
/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size,
/// the error [struct][DecompressError] will contain the status [`TINFLStatus::HasMoreOutput`] and the data that was decompressed on failure.
///
/// As this function tries to decompress everything in one go, it's not ideal for general use outside of tests or where the output size is expected to be small.
/// It is suggested to use streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead.
///
/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] on failure.
#[inline]
#[cfg(feature = "with-alloc")]
pub fn decompress_to_vec_zlib_with_limit(
    input: &[u8],
    max_size: usize,
) -> Result<Vec<u8>, DecompressError> {
    decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, max_size)
}

/// Backend of various to-[`Vec`] decompressions.
///
/// Returns [`Vec`] of decompressed data on success and the [error struct][DecompressError] with details on failure.
#[cfg(feature = "with-alloc")]
fn decompress_to_vec_inner(
    input: &[u8],
    flags: u32,
    max_output_size: usize,
) -> Result<Vec<u8>, DecompressError> {
    let flags = flags | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
    let mut ret: Vec<u8> = vec![0; input.len().saturating_mul(2).min(max_output_size)];

    let mut decomp = Box::<DecompressorOxide>::default();

    let mut in_pos = 0;
    let mut out_pos = 0;
    loop {
        // Wrap the whole output slice so we know we have enough of the
        // decompressed data for matches.
        let (status, in_consumed, out_consumed) =
            decompress(&mut decomp, &input[in_pos..], &mut ret, out_pos, flags);
        in_pos += in_consumed;
        out_pos += out_consumed;

        match status {
            TINFLStatus::Done => {
                ret.truncate(out_pos);
                return Ok(ret);
            }

            TINFLStatus::HasMoreOutput => {
                // if the buffer has already reached the size limit, return an error
                if ret.len() >= max_output_size {
                    return decompress_error(TINFLStatus::HasMoreOutput, ret);
                }
                // calculate the new length, capped at `max_output_size`
                let new_len = ret.len().saturating_mul(2).min(max_output_size);
                ret.resize(new_len, 0);
            }

            _ => return decompress_error(status, ret),
        }
    }
}

/// Decompress one or more source slices from an iterator into the output slice.
///
/// * On success, returns the number of bytes that were written.
/// * On failure, returns the failure status code.
///
/// This will fail if the output buffer is not large enough, but in that case
/// the output buffer will still contain the partial decompression.
///
/// * `out` the output buffer.
/// * `it` the iterator of input slices.
/// * `zlib_header` if the first slice out of the iterator is expected to have a
///   Zlib header. Otherwise the slices are assumed to be the deflate data only.
/// * `ignore_adler32` if the adler32 checksum should be calculated or not.
pub fn decompress_slice_iter_to_slice<'out, 'inp>(
    out: &'out mut [u8],
    it: impl Iterator<Item = &'inp [u8]>,
    zlib_header: bool,
    ignore_adler32: bool,
) -> Result<usize, TINFLStatus> {
    use self::core::inflate_flags::*;

    let mut it = it.peekable();
    let r = &mut DecompressorOxide::new();
    let mut out_pos = 0;
    while let Some(in_buf) = it.next() {
        let has_more = it.peek().is_some();
        let flags = {
            let mut f = TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
            if zlib_header {
                f |= TINFL_FLAG_PARSE_ZLIB_HEADER;
            }
            if ignore_adler32 {
                f |= TINFL_FLAG_IGNORE_ADLER32;
            }
            if has_more {
                f |= TINFL_FLAG_HAS_MORE_INPUT;
            }
            f
        };
        let (status, _input_read, bytes_written) = decompress(r, in_buf, out, out_pos, flags);
        out_pos += bytes_written;
        match status {
            TINFLStatus::NeedsMoreInput => continue,
            TINFLStatus::Done => return Ok(out_pos),
            e => return Err(e),
        }
    }
    // If we ran out of source slices without getting a `Done` from the
    // decompression we can call it a failure.
    Err(TINFLStatus::FailedCannotMakeProgress)
}

#[cfg(test)]
mod test {
    use super::{
        decompress_slice_iter_to_slice, decompress_to_vec_zlib, decompress_to_vec_zlib_with_limit,
        DecompressError, TINFLStatus,
    };
    const ENCODED: [u8; 20] = [
        120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19,
    ];

    #[test]
    fn decompress_vec() {
        let res = decompress_to_vec_zlib(&ENCODED[..]).unwrap();
        assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]);
    }

    #[test]
    fn decompress_vec_with_high_limit() {
        let res = decompress_to_vec_zlib_with_limit(&ENCODED[..], 100_000).unwrap();
        assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]);
    }

    #[test]
    fn fail_to_decompress_with_limit() {
        let res = decompress_to_vec_zlib_with_limit(&ENCODED[..], 8);
        match res {
            Err(DecompressError {
                status: TINFLStatus::HasMoreOutput,
                ..
            }) => (), // expected result
            _ => panic!("Decompression output size limit was not enforced"),
        }
    }

    #[test]
    fn test_decompress_slice_iter_to_slice() {
        // one slice
        let mut out = [0_u8; 12_usize];
        let r =
            decompress_slice_iter_to_slice(&mut out, Some(&ENCODED[..]).into_iter(), true, false);
        assert_eq!(r, Ok(12));
        assert_eq!(&out[..12], &b"Hello, zlib!"[..]);

        // some chunks at a time
        for chunk_size in 1..13 {
            // Note: because of https://github.com/Frommi/miniz_oxide/issues/110 our
            // out buffer needs to have +1 byte available when the chunk size cuts
            // the adler32 data off from the last actual data.
            let mut out = [0_u8; 12_usize + 1];
            let r =
                decompress_slice_iter_to_slice(&mut out, ENCODED.chunks(chunk_size), true, false);
            assert_eq!(r, Ok(12));
            assert_eq!(&out[..12], &b"Hello, zlib!"[..]);
        }

        // output buffer too small
        let mut out = [0_u8; 3_usize];
        let r = decompress_slice_iter_to_slice(&mut out, ENCODED.chunks(7), true, false);
        assert!(r.is_err());
    }
}
<|endoftext|>