<commit_before>use super::{Result, Error};
use super::model::*;

/// The websocket protocol version expected.
const VERSION: u64 = 3;

/// Known state composed from received events.
pub struct State {
	user: CurrentUser,
	session_id: String,
	private_channels: Vec<PrivateChannel>,
	servers: Vec<LiveServer>,
}

impl State {
	pub fn new(ready: ReadyEvent) -> Result<State> {
		if ready.version != VERSION {
			println!("[Warning] Got version {} instead of {}", ready.version, VERSION);
			return Err(Error::Other("Wrong protocol version"))
		}
		Ok(State {
			user: ready.user,
			session_id: ready.session_id,
			private_channels: ready.private_channels,
			servers: ready.servers
		})
	}

	pub fn update(&mut self, event: &Event) {
		match *event {
			Event::UserUpdate(ref user) => self.user = user.clone(),
			Event::VoiceStateUpdate(ref server, ref state) => {
				self.servers.iter_mut().find(|s| s.id == *server).map(|srv| {
					match srv.voice_states.iter_mut().find(|u| u.user_id == state.user_id) {
						Some(srv_state) => { srv_state.clone_from(state); return }
						None => {}
					}
					srv.voice_states.push(state.clone());
				});
			}
			Event::PresenceUpdate { ref server_id, ref presence, ref user, roles: _ } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					// If the user was modified, update the member list
					if let &Some(ref user) = user {
						srv.members.iter_mut().find(|u| u.user.id == user.id).map(|member| {
							member.user.clone_from(&user);
						});
					}
					if presence.status == OnlineStatus::Offline {
						// Remove the user from the presence list
						srv.presences.retain(|u| u.user_id != presence.user_id);
					} else {
						// Update the presence list with the new information
						match srv.presences.iter_mut().find(|u| u.user_id == presence.user_id) {
							Some(srv_presence) => { srv_presence.clone_from(presence); return }
							None => {}
						}
						srv.presences.push(presence.clone());
					}
				});
			}
			Event::ServerCreate(ref server) => self.servers.push(server.clone()),
			Event::ServerUpdate(ref server) => {
				self.servers.iter_mut().find(|s| s.id == server.id).map(|srv| {
					srv.name.clone_from(&server.name);
					srv.joined_at.clone_from(&server.joined_at);
					srv.afk_timeout = server.afk_timeout;
					srv.afk_channel_id.clone_from(&server.afk_channel_id);
					srv.icon.clone_from(&server.icon);
					srv.roles.clone_from(&server.roles);
					srv.region.clone_from(&server.region);
					// embed_enabled and embed_channel_id skipped
					srv.owner_id.clone_from(&server.owner_id);
				});
			}
			Event::ServerDelete(ref server) => self.servers.retain(|s| s.id != server.id),
			Event::ServerMemberAdd { ref server_id, ref joined_at, ref roles, ref user } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.members.push(Member {
						user: user.clone(),
						roles: roles.clone(),
						joined_at: joined_at.clone(),
						mute: false,
						deaf: false,
					})
				});
			}
			Event::ServerMemberUpdate { ref server_id, ref roles, ref user } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.members.iter_mut().find(|m| m.user.id == user.id).map(|member| {
						member.user.clone_from(user);
						member.roles.clone_from(roles);
					})
				});
			}
			Event::ServerMemberRemove(ref server_id, ref user) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.members.retain(|m| m.user.id != user.id);
				});
			}
			Event::ServerRoleCreate(ref server_id, ref role) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.push(role.clone());
				});
			}
			Event::ServerRoleUpdate(ref server_id, ref role) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.iter_mut().find(|r| r.id == role.id).map(|srv_role| {
						srv_role.clone_from(role);
					});
				});
			}
			Event::ServerRoleDelete(ref server_id, ref role_id) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.retain(|r| r.id != *role_id);
				});
			}
			Event::ChannelCreate(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.push(channel.clone());
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.push(channel.clone());
					});
				}
			},
			Event::ChannelUpdate(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.iter_mut().find(|c| c.id == channel.id).map(|chan| {
						chan.clone_from(channel);
					});
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.iter_mut().find(|c| c.id == channel.id).map(|chan| {
							chan.clone_from(channel);
						})
					});
				}
			},
			Event::ChannelDelete(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.retain(|c| c.id != channel.id);
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.retain(|c| c.id != channel.id);
					});
				}
			},
			_ => {}
		}
	}

	#[inline]
	pub fn user(&self) -> &CurrentUser { &self.user }

	#[inline]
	pub fn session_id(&self) -> &str { &self.session_id }

	#[inline]
	pub fn private_channels(&self) -> &[PrivateChannel] { &self.private_channels }

	#[inline]
	pub fn servers(&self) -> &[LiveServer] { &self.servers }

	pub fn find_channel(&self, id: &ChannelId) -> Option<ChannelRef> {
		for server in &self.servers {
			for channel in &server.channels {
				if channel.id == *id {
					return Some(ChannelRef::Public(server, channel))
				}
			}
		}
		for channel in &self.private_channels {
			if channel.id == *id {
				return Some(ChannelRef::Private(channel))
			}
		}
		None
	}
}

/// A reference to a private or public channel
pub enum ChannelRef<'a> {
	/// A private channel
	Private(&'a PrivateChannel),
	/// A public channel and its server
	Public(&'a LiveServer, &'a PublicChannel),
}
<commit_msg>Improve state handling for VoiceStates<commit_after>use super::{Result, Error};
use super::model::*;

/// The websocket protocol version expected.
const VERSION: u64 = 3;

/// Known state composed from received events.
pub struct State {
	user: CurrentUser,
	session_id: String,
	private_channels: Vec<PrivateChannel>,
	servers: Vec<LiveServer>,
}

impl State {
	pub fn new(ready: ReadyEvent) -> Result<State> {
		if ready.version != VERSION {
			println!("[Warning] Got version {} instead of {}", ready.version, VERSION);
			return Err(Error::Other("Wrong protocol version"))
		}
		Ok(State {
			user: ready.user,
			session_id: ready.session_id,
			private_channels: ready.private_channels,
			servers: ready.servers
		})
	}

	pub fn update(&mut self, event: &Event) {
		match *event {
			Event::UserUpdate(ref user) => self.user = user.clone(),
			Event::VoiceStateUpdate(ref server, ref state) => {
				self.servers.iter_mut().find(|s| s.id == *server).map(|srv| {
					if !state.channel_id.is_some() {
						// Remove the user from the voice state list
						srv.voice_states.retain(|v| v.user_id != state.user_id);
					} else {
						// Update or add to the voice state list
						match srv.voice_states.iter_mut().find(|u| u.user_id == state.user_id) {
							Some(srv_state) => { srv_state.clone_from(state); return }
							None => {}
						}
						srv.voice_states.push(state.clone());
					}
				});
			}
			Event::PresenceUpdate { ref server_id, ref presence, ref user, roles: _ } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					// If the user was modified, update the member list
					if let &Some(ref user) = user {
						srv.members.iter_mut().find(|u| u.user.id == user.id).map(|member| {
							member.user.clone_from(&user);
						});
					}
					if presence.status == OnlineStatus::Offline {
						// Remove the user from the presence list
						srv.presences.retain(|u| u.user_id != presence.user_id);
					} else {
						// Update or add to the presence list
						match srv.presences.iter_mut().find(|u| u.user_id == presence.user_id) {
							Some(srv_presence) => { srv_presence.clone_from(presence); return }
							None => {}
						}
						srv.presences.push(presence.clone());
					}
				});
			}
			Event::ServerCreate(ref server) => self.servers.push(server.clone()),
			Event::ServerUpdate(ref server) => {
				self.servers.iter_mut().find(|s| s.id == server.id).map(|srv| {
					srv.name.clone_from(&server.name);
					srv.joined_at.clone_from(&server.joined_at);
					srv.afk_timeout = server.afk_timeout;
					srv.afk_channel_id.clone_from(&server.afk_channel_id);
					srv.icon.clone_from(&server.icon);
					srv.roles.clone_from(&server.roles);
					srv.region.clone_from(&server.region);
					// embed_enabled and embed_channel_id skipped
					srv.owner_id.clone_from(&server.owner_id);
				});
			}
			Event::ServerDelete(ref server) => self.servers.retain(|s| s.id != server.id),
			Event::ServerMemberAdd { ref server_id, ref joined_at, ref roles, ref user } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.members.push(Member {
						user: user.clone(),
						roles: roles.clone(),
						joined_at: joined_at.clone(),
						mute: false,
						deaf: false,
					})
				});
			}
			Event::ServerMemberUpdate { ref server_id, ref roles, ref user } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.members.iter_mut().find(|m| m.user.id == user.id).map(|member| {
						member.user.clone_from(user);
						member.roles.clone_from(roles);
					})
				});
			}
			Event::ServerMemberRemove(ref server_id, ref user) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.members.retain(|m| m.user.id != user.id);
				});
			}
			Event::ServerRoleCreate(ref server_id, ref role) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.push(role.clone());
				});
			}
			Event::ServerRoleUpdate(ref server_id, ref role) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.iter_mut().find(|r| r.id == role.id).map(|srv_role| {
						srv_role.clone_from(role);
					});
				});
			}
			Event::ServerRoleDelete(ref server_id, ref role_id) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.retain(|r| r.id != *role_id);
				});
			}
			Event::ChannelCreate(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.push(channel.clone());
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.push(channel.clone());
					});
				}
			},
			Event::ChannelUpdate(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.iter_mut().find(|c| c.id == channel.id).map(|chan| {
						chan.clone_from(channel);
					});
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.iter_mut().find(|c| c.id == channel.id).map(|chan| {
							chan.clone_from(channel);
						})
					});
				}
			},
			Event::ChannelDelete(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.retain(|c| c.id != channel.id);
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.retain(|c| c.id != channel.id);
					});
				}
			},
			_ => {}
		}
	}

	#[inline]
	pub fn user(&self) -> &CurrentUser { &self.user }

	#[inline]
	pub fn session_id(&self) -> &str { &self.session_id }

	#[inline]
	pub fn private_channels(&self) -> &[PrivateChannel] { &self.private_channels }

	#[inline]
	pub fn servers(&self) -> &[LiveServer] { &self.servers }

	pub fn find_channel(&self, id: &ChannelId) -> Option<ChannelRef> {
		for server in &self.servers {
			for channel in &server.channels {
				if channel.id == *id {
					return Some(ChannelRef::Public(server, channel))
				}
			}
		}
		for channel in &self.private_channels {
			if channel.id == *id {
				return Some(ChannelRef::Private(channel))
			}
		}
		None
	}
}

/// A reference to a private or public channel
pub enum ChannelRef<'a> {
	/// A private channel
	Private(&'a PrivateChannel),
	/// A public channel and its server
	Public(&'a LiveServer, &'a PublicChannel),
}
<|endoftext|>


<commit_before>use ngrams::ngrams;

#[test]
fn unigrams() {
    let text = "Estimates";
    let unigrams: Vec<_> = ngrams(text, 1).collect();
    assert_eq!(unigrams, ["E", "s", "t", "i", "m", "a", "t", "e", "s"]);
}

#[test]
fn bigrams() {
    let text = "Estimates";
    let bigrams: Vec<_> = ngrams(text, 2).collect();
    assert_eq!(bigrams, ["Es", "st", "ti", "im", "ma", "at", "te", "es"]);
}

#[test]
fn trigrams() {
    let text = "Estimates";
    let trigrams: Vec<_> = ngrams(text, 3).collect();
    assert_eq!(trigrams, ["Est", "sti", "tim", "ima", "mat", "ate", "tes"]);
}

#[test]
fn longer_than_string_ngrams() {
    let text = "String";
    let sevengrams: Vec<String> = ngrams(text, 7).collect();
    let empty_vector: Vec<String> = Vec::new();
    assert_eq!(sevengrams, empty_vector);
}
<commit_msg>Rust can infer the type of vector in most cases<commit_after>use ngrams::ngrams;

#[test]
fn unigrams() {
    let text = "Estimates";
    let unigrams: Vec<_> = ngrams(text, 1).collect();
    assert_eq!(unigrams, ["E", "s", "t", "i", "m", "a", "t", "e", "s"]);
}

#[test]
fn bigrams() {
    let text = "Estimates";
    let bigrams: Vec<_> = ngrams(text, 2).collect();
    assert_eq!(bigrams, ["Es", "st", "ti", "im", "ma", "at", "te", "es"]);
}

#[test]
fn trigrams() {
    let text = "Estimates";
    let trigrams: Vec<_> = ngrams(text, 3).collect();
    assert_eq!(trigrams, ["Est", "sti", "tim", "ima", "mat", "ate", "tes"]);
}

#[test]
fn longer_than_string_ngrams() {
    let text = "String";
    let sevengrams: Vec<_> = ngrams(text, 7).collect();
    let empty_vector: Vec<String> = Vec::new();
    assert_eq!(sevengrams, empty_vector);
}
<|endoftext|>


<commit_before>//! Types for Gerber code generation.
//!
//! All types are stateless, meaning that they contain all information in order
//! to render themselves. This means for example that each `Coordinates`
//! instance contains a reference to the coordinate format to be used.

use std::convert::{From, Into};

use ::{CoordinateFormat, CoordinateNumber};

/// Coordinates are part of an operation.
///
/// Coordinates are modal. If an X is omitted, the X coordinate of the
/// current point is used. Similar for Y.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Coordinates {
    pub x: Option<CoordinateNumber>,
    pub y: Option<CoordinateNumber>,
    pub format: CoordinateFormat,
}

impl Coordinates {
    pub fn new<T, U>(x: T, y: U, format: CoordinateFormat) -> Self
            where T: Into<CoordinateNumber>, U: Into<CoordinateNumber> {
        Coordinates { x: Some(x.into()), y: Some(y.into()), format: format }
    }

    pub fn at_x<T>(x: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        Coordinates { x: Some(x.into()), y: None, format: format }
    }

    pub fn at_y<T>(y: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        Coordinates { x: None, y: Some(y.into()), format: format }
    }
}

/// Coordinate offsets can be used for interpolate operations in circular
/// interpolation mode.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoordinateOffset {
    pub x: Option<CoordinateNumber>,
    pub y: Option<CoordinateNumber>,
    pub format: CoordinateFormat,
}

impl CoordinateOffset {
    pub fn new<T, U>(x: T, y: U, format: CoordinateFormat) -> Self
            where T: Into<CoordinateNumber>, U: Into<CoordinateNumber> {
        CoordinateOffset { x: Some(x.into()), y: Some(y.into()), format: format }
    }

    pub fn at_x<T>(x: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        CoordinateOffset { x: Some(x.into()), y: None, format: format }
    }

    pub fn at_y<T>(y: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        CoordinateOffset { x: None, y: Some(y.into()), format: format }
    }
}

// Helper macros

macro_rules! impl_from {
    ($from:ty, $target:ty, $variant:expr) => {
        impl From<$from> for $target {
            fn from(val: $from) -> Self {
                $variant(val)
            }
        }
    }
}

// Root type

#[derive(Debug, Clone, PartialEq)]
pub enum Command {
    FunctionCode(FunctionCode),
    ExtendedCode(ExtendedCode),
}

impl_from!(FunctionCode, Command, Command::FunctionCode);
impl_from!(ExtendedCode, Command, Command::ExtendedCode);

// Main categories

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FunctionCode {
    DCode(DCode),
    GCode(GCode),
    MCode(MCode),
}

impl_from!(DCode, FunctionCode, FunctionCode::DCode);
impl_from!(GCode, FunctionCode, FunctionCode::GCode);
impl_from!(MCode, FunctionCode, FunctionCode::MCode);

#[derive(Debug, Clone, PartialEq)]
pub enum ExtendedCode {
    /// FS
    CoordinateFormat(CoordinateFormat),
    /// MO
    Unit(Unit),
    /// AD
    ApertureDefinition(ApertureDefinition),
    /// AM
    ApertureMacro(::macros::ApertureMacro),
    /// LP
    LoadPolarity(Polarity),
    /// SR
    StepAndRepeat(StepAndRepeat),
    /// TF
    FileAttribute(::attributes::FileAttribute),
    /// TA
    ApertureAttribute(::attributes::ApertureAttribute),
    /// TD
    DeleteAttribute(String),
}

impl_from!(CoordinateFormat, ExtendedCode, ExtendedCode::CoordinateFormat);
impl_from!(Unit, ExtendedCode, ExtendedCode::Unit);
impl_from!(ApertureDefinition, ExtendedCode, ExtendedCode::ApertureDefinition);
impl_from!(::macros::ApertureMacro, ExtendedCode, ExtendedCode::ApertureMacro);
impl_from!(Polarity, ExtendedCode, ExtendedCode::LoadPolarity);
impl_from!(StepAndRepeat, ExtendedCode, ExtendedCode::StepAndRepeat);
impl_from!(::attributes::FileAttribute, ExtendedCode, ExtendedCode::FileAttribute);
impl_from!(::attributes::ApertureAttribute, ExtendedCode, ExtendedCode::ApertureAttribute);

// Function codes

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DCode {
    Operation(Operation),
    SelectAperture(i32),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GCode {
    InterpolationMode(InterpolationMode),
    RegionMode(bool),
    QuadrantMode(QuadrantMode),
    Comment(String),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MCode {
    EndOfFile,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operation {
    /// D01 Command
    Interpolate(Coordinates, Option<CoordinateOffset>),
    /// D02 Command
    Move(Coordinates),
    /// D03 Command
    Flash(Coordinates),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InterpolationMode {
    Linear,
    ClockwiseCircular,
    CounterclockwiseCircular,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuadrantMode {
    Single,
    Multi,
}

// Extended codes

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Unit {
    Inches,
    Millimeters,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ApertureDefinition {
    pub code: i32,
    pub aperture: Aperture,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Aperture {
    Circle(Circle),
    Rectangle(Rectangular),
    Obround(Rectangular),
    Polygon(Polygon),
    Other(String),
}

#[derive(Debug, Clone, PartialEq)]
pub struct Circle {
    pub diameter: f64,
    pub hole_diameter: Option<f64>,
}

impl Circle {
    pub fn new(diameter: f64) -> Self {
        Circle {
            diameter: diameter,
            hole_diameter: None,
        }
    }

    pub fn with_hole(diameter: f64, hole_diameter: f64) -> Self {
        Circle {
            diameter: diameter,
            hole_diameter: Some(hole_diameter),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Rectangular {
    pub x: f64,
    pub y: f64,
    pub hole_diameter: Option<f64>,
}

impl Rectangular {
    pub fn new(x: f64, y: f64) -> Self {
        Rectangular {
            x: x,
            y: y,
            hole_diameter: None,
        }
    }

    pub fn with_hole(x: f64, y: f64, hole_diameter: f64) -> Self {
        Rectangular {
            x: x,
            y: y,
            hole_diameter: Some(hole_diameter),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Polygon {
    pub diameter: f64,
    pub vertices: u8, // 3--12
    pub rotation: Option<f64>,
    pub hole_diameter: Option<f64>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Polarity {
    Clear,
    Dark,
}

#[derive(Debug, Clone, PartialEq)]
pub enum StepAndRepeat {
    Open { repeat_x: u32, repeat_y: u32, distance_x: f64, distance_y: f64 },
    Close,
}

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

    use ::{CoordinateNumber, CoordinateFormat};
    use super::*;

    #[test]
    fn test_debug() {
        //! The debug representation should work properly.
        let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment("test".to_string())));
        let debug = format!("{:?}", c);
        assert_eq!(debug, "FunctionCode(GCode(Comment(\"test\")))");
    }

    #[test]
    fn test_coordinates_into() {
        let cf = CoordinateFormat::new(2, 4);
        let c1 = Coordinates::new(CoordinateNumber::from(1), CoordinateNumber::from(2), cf);
        let c2 = Coordinates::new(1, 2, cf);
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_coordinates_into_mixed() {
        let cf = CoordinateFormat::new(2, 4);
        let c1 = Coordinates::new(CoordinateNumber::from(1), 2, cf);
        let c2 = Coordinates::new(1, 2, cf);
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_circle_new() {
        let c1 = Circle::new(3.0);
        let c2 = Circle { diameter: 3.0, hole_diameter: None };
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_circle_with_hole() {
        let c1 = Circle::with_hole(3.0, 1.0);
        let c2 = Circle { diameter: 3.0, hole_diameter: Some(1.0) };
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_rectangular_new() {
        let r1 = Rectangular::new(2.0, 3.0);
        let r2 = Rectangular { x: 2.0, y: 3.0, hole_diameter: None };
        assert_eq!(r1, r2);
    }

    #[test]
    fn test_rectangular_with_hole() {
        let r1 = Rectangular::with_hole(3.0, 2.0, 1.0);
        let r2 = Rectangular { x: 3.0, y: 2.0, hole_diameter: Some(1.0) };
        assert_eq!(r1, r2);
    }

    #[test]
    fn test_command_from_function_code() {
        let comment = FunctionCode::GCode(GCode::Comment("hello".into()));
        let c1: Command = Command::FunctionCode(comment.clone());
        let c2: Command = comment.into();
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_command_from_extended_code() {
        let delete_attr = ExtendedCode::DeleteAttribute("hello".into());
        let c1: Command = Command::ExtendedCode(delete_attr.clone());
        let c2: Command = delete_attr.into();
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_function_code_from_gcode() {
        let comment = GCode::Comment("hello".into());
        let f1: FunctionCode = FunctionCode::GCode(comment.clone());
        let f2: FunctionCode = comment.into();
        assert_eq!(f1, f2);
    }

    #[test]
    fn test_extended_code_from_polarity() {
        let e1: ExtendedCode = ExtendedCode::LoadPolarity(Polarity::Dark);
        let e2: ExtendedCode = Polarity::Dark.into();
        assert_eq!(e1, e2);
    }

}
<commit_msg>Add second level of From impls for Command<commit_after>//! Types for Gerber code generation.
//!
//! All types are stateless, meaning that they contain all information in order
//! to render themselves. This means for example that each `Coordinates`
//! instance contains a reference to the coordinate format to be used.

use std::convert::{From, Into};

use ::{CoordinateFormat, CoordinateNumber};

/// Coordinates are part of an operation.
///
/// Coordinates are modal. If an X is omitted, the X coordinate of the
/// current point is used. Similar for Y.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Coordinates {
    pub x: Option<CoordinateNumber>,
    pub y: Option<CoordinateNumber>,
    pub format: CoordinateFormat,
}

impl Coordinates {
    pub fn new<T, U>(x: T, y: U, format: CoordinateFormat) -> Self
            where T: Into<CoordinateNumber>, U: Into<CoordinateNumber> {
        Coordinates { x: Some(x.into()), y: Some(y.into()), format: format }
    }

    pub fn at_x<T>(x: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        Coordinates { x: Some(x.into()), y: None, format: format }
    }

    pub fn at_y<T>(y: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        Coordinates { x: None, y: Some(y.into()), format: format }
    }
}

/// Coordinate offsets can be used for interpolate operations in circular
/// interpolation mode.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CoordinateOffset {
    pub x: Option<CoordinateNumber>,
    pub y: Option<CoordinateNumber>,
    pub format: CoordinateFormat,
}

impl CoordinateOffset {
    pub fn new<T, U>(x: T, y: U, format: CoordinateFormat) -> Self
            where T: Into<CoordinateNumber>, U: Into<CoordinateNumber> {
        CoordinateOffset { x: Some(x.into()), y: Some(y.into()), format: format }
    }

    pub fn at_x<T>(x: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        CoordinateOffset { x: Some(x.into()), y: None, format: format }
    }

    pub fn at_y<T>(y: T, format: CoordinateFormat) -> Self where T: Into<CoordinateNumber> {
        CoordinateOffset { x: None, y: Some(y.into()), format: format }
    }
}

// Helper macros

macro_rules! impl_from {
    ($from:ty, $target:ty, $variant:expr) => {
        impl From<$from> for $target {
            fn from(val: $from) -> Self {
                $variant(val)
            }
        }
    }
}

// Root type

#[derive(Debug, Clone, PartialEq)]
pub enum Command {
    FunctionCode(FunctionCode),
    ExtendedCode(ExtendedCode),
}

impl_from!(FunctionCode, Command, Command::FunctionCode);
impl_from!(ExtendedCode, Command, Command::ExtendedCode);

macro_rules! impl_command_fromfrom {
    ($from:ty, $inner:path) => {
        impl From<$from> for Command {
            fn from(val: $from) -> Self {
                Command::from($inner(val))
            }
        }
    }
}

// Main categories

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FunctionCode {
    DCode(DCode),
    GCode(GCode),
    MCode(MCode),
}

impl_from!(DCode, FunctionCode, FunctionCode::DCode);
impl_from!(GCode, FunctionCode, FunctionCode::GCode);
impl_from!(MCode, FunctionCode, FunctionCode::MCode);

impl_command_fromfrom!(DCode, FunctionCode::from);
impl_command_fromfrom!(GCode, FunctionCode::from);
impl_command_fromfrom!(MCode, FunctionCode::from);

#[derive(Debug, Clone, PartialEq)]
pub enum ExtendedCode {
    /// FS
    CoordinateFormat(CoordinateFormat),
    /// MO
    Unit(Unit),
    /// AD
    ApertureDefinition(ApertureDefinition),
    /// AM
    ApertureMacro(::macros::ApertureMacro),
    /// LP
    LoadPolarity(Polarity),
    /// SR
    StepAndRepeat(StepAndRepeat),
    /// TF
    FileAttribute(::attributes::FileAttribute),
    /// TA
    ApertureAttribute(::attributes::ApertureAttribute),
    /// TD
    DeleteAttribute(String),
}

impl_from!(CoordinateFormat, ExtendedCode, ExtendedCode::CoordinateFormat);
impl_from!(Unit, ExtendedCode, ExtendedCode::Unit);
impl_from!(ApertureDefinition, ExtendedCode, ExtendedCode::ApertureDefinition);
impl_from!(::macros::ApertureMacro, ExtendedCode, ExtendedCode::ApertureMacro);
impl_from!(Polarity, ExtendedCode, ExtendedCode::LoadPolarity);
impl_from!(StepAndRepeat, ExtendedCode, ExtendedCode::StepAndRepeat);
impl_from!(::attributes::FileAttribute, ExtendedCode, ExtendedCode::FileAttribute);
impl_from!(::attributes::ApertureAttribute, ExtendedCode, ExtendedCode::ApertureAttribute);

impl_command_fromfrom!(CoordinateFormat, ExtendedCode::from);
impl_command_fromfrom!(Unit, ExtendedCode::from);
impl_command_fromfrom!(ApertureDefinition, ExtendedCode::from);
impl_command_fromfrom!(::macros::ApertureMacro, ExtendedCode::from);
impl_command_fromfrom!(Polarity, ExtendedCode::from);
impl_command_fromfrom!(StepAndRepeat, ExtendedCode::from);
impl_command_fromfrom!(::attributes::FileAttribute, ExtendedCode::from);
impl_command_fromfrom!(::attributes::ApertureAttribute, ExtendedCode::from);

// Function codes

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DCode {
    Operation(Operation),
    SelectAperture(i32),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GCode {
    InterpolationMode(InterpolationMode),
    RegionMode(bool),
    QuadrantMode(QuadrantMode),
    Comment(String),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MCode {
    EndOfFile,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operation {
    /// D01 Command
    Interpolate(Coordinates, Option<CoordinateOffset>),
    /// D02 Command
    Move(Coordinates),
    /// D03 Command
    Flash(Coordinates),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InterpolationMode {
    Linear,
    ClockwiseCircular,
    CounterclockwiseCircular,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuadrantMode {
    Single,
    Multi,
}

// Extended codes

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Unit {
    Inches,
    Millimeters,
}

#[derive(Debug, Clone, PartialEq)]
pub struct ApertureDefinition {
    pub code: i32,
    pub aperture: Aperture,
}

#[derive(Debug, Clone, PartialEq)]
pub enum Aperture {
    Circle(Circle),
    Rectangle(Rectangular),
    Obround(Rectangular),
    Polygon(Polygon),
    Other(String),
}

#[derive(Debug, Clone, PartialEq)]
pub struct Circle {
    pub diameter: f64,
    pub hole_diameter: Option<f64>,
}

impl Circle {
    pub fn new(diameter: f64) -> Self {
        Circle {
            diameter: diameter,
            hole_diameter: None,
        }
    }

    pub fn with_hole(diameter: f64, hole_diameter: f64) -> Self {
        Circle {
            diameter: diameter,
            hole_diameter: Some(hole_diameter),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Rectangular {
    pub x: f64,
    pub y: f64,
    pub hole_diameter: Option<f64>,
}

impl Rectangular {
    pub fn new(x: f64, y: f64) -> Self {
        Rectangular {
            x: x,
            y: y,
            hole_diameter: None,
        }
    }

    pub fn with_hole(x: f64, y: f64, hole_diameter: f64) -> Self {
        Rectangular {
            x: x,
            y: y,
            hole_diameter: Some(hole_diameter),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct Polygon {
    pub diameter: f64,
    pub vertices: u8, // 3--12
    pub rotation: Option<f64>,
    pub hole_diameter: Option<f64>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Polarity {
    Clear,
    Dark,
}

#[derive(Debug, Clone, PartialEq)]
pub enum StepAndRepeat {
    Open { repeat_x: u32, repeat_y: u32, distance_x: f64, distance_y: f64 },
    Close,
}

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

    use ::{CoordinateNumber, CoordinateFormat};
    use super::*;

    #[test]
    fn test_debug() {
        //! The debug representation should work properly.
        let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment("test".to_string())));
        let debug = format!("{:?}", c);
        assert_eq!(debug, "FunctionCode(GCode(Comment(\"test\")))");
    }

    #[test]
    fn test_coordinates_into() {
        let cf = CoordinateFormat::new(2, 4);
        let c1 = Coordinates::new(CoordinateNumber::from(1), CoordinateNumber::from(2), cf);
        let c2 = Coordinates::new(1, 2, cf);
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_coordinates_into_mixed() {
        let cf = CoordinateFormat::new(2, 4);
        let c1 = Coordinates::new(CoordinateNumber::from(1), 2, cf);
        let c2 = Coordinates::new(1, 2, cf);
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_circle_new() {
        let c1 = Circle::new(3.0);
        let c2 = Circle { diameter: 3.0, hole_diameter: None };
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_circle_with_hole() {
        let c1 = Circle::with_hole(3.0, 1.0);
        let c2 = Circle { diameter: 3.0, hole_diameter: Some(1.0) };
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_rectangular_new() {
        let r1 = Rectangular::new(2.0, 3.0);
        let r2 = Rectangular { x: 2.0, y: 3.0, hole_diameter: None };
        assert_eq!(r1, r2);
    }

    #[test]
    fn test_rectangular_with_hole() {
        let r1 = Rectangular::with_hole(3.0, 2.0, 1.0);
        let r2 = Rectangular { x: 3.0, y: 2.0, hole_diameter: Some(1.0) };
        assert_eq!(r1, r2);
    }

    #[test]
    fn test_command_from_function_code() {
        let comment = FunctionCode::GCode(GCode::Comment("hello".into()));
        let c1: Command = Command::FunctionCode(comment.clone());
        let c2: Command = comment.into();
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_command_from_extended_code() {
        let delete_attr = ExtendedCode::DeleteAttribute("hello".into());
        let c1: Command = Command::ExtendedCode(delete_attr.clone());
        let c2: Command = delete_attr.into();
        assert_eq!(c1, c2);
    }

    #[test]
    fn test_function_code_from_gcode() {
        let comment = GCode::Comment("hello".into());
        let f1: FunctionCode = FunctionCode::GCode(comment.clone());
        let f2: FunctionCode = comment.into();
        assert_eq!(f1, f2);
    }

    #[test]
    fn test_extended_code_from_polarity() {
        let e1: ExtendedCode = ExtendedCode::LoadPolarity(Polarity::Dark);
        let e2: ExtendedCode = Polarity::Dark.into();
        assert_eq!(e1, e2);
    }

}
<|endoftext|>


<commit_before>use super::core::str::as_bytes;
use super::core::slice::iter;
use super::core::iter::Iterator;
use super::core::option::{Some, None};

static VGA_WIDTH  : u16 = 80;
static VGA_HEIGHT : u16 = 24;

static mut curr_x: u16 = 0;
static mut curr_y: u16 = 0;

static mut fg_color: Color = Green;
static mut bg_color: Color = Black;

pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

fn range(lo: uint, hi: uint, it: |uint| ) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

pub fn clear_screen() {
    unsafe {
        range(0, 80*25, |i| {
            *((0xb8000 + i * 2) as *mut u16) = make_vgaentry(0, fg_color, bg_color);

        });
    }
}

pub fn backspace() {
    unsafe {
        if (curr_x == 0) {
            curr_y -= 1;
            curr_x = VGA_WIDTH - 1;
        } else {
            curr_x -= 1;
        }
        putchar(curr_x, curr_y, 0);
    }
}

pub fn putc(c: u8) {
    unsafe {
        putchar(curr_x, curr_y, c);
        curr_x += 1;
        if (curr_x > VGA_WIDTH) {
            curr_x -= VGA_WIDTH;
            curr_y += 1;
        }
    }
}

pub fn newline() {
    unsafe {
        curr_x = 0;
        curr_y += 1;
    }
}

pub fn putchar(x: u16, y: u16, c: u8) {
    if (x >= VGA_WIDTH || y >= VGA_HEIGHT) {
        return;
    }
    let idx : uint =  (y * VGA_WIDTH * 2 + x * 2) as uint;
    unsafe {
        *((0xb8000 + idx) as *mut u16) = make_vgaentry(c, fg_color, bg_color);
    }
}

fn make_vgaentry(c: u8, fg: Color, bg: Color) -> u16 {
    let color = fg as u16 | (bg as u16 << 4);
    return c as u16 | (color << 8);
}

pub fn write(x: u16, y: u16, s: &str) {
    let bytes : &[u8] = as_bytes(s);
    let mut ix = x;
    let mut iy = y;
    for b in super::core::slice::iter(bytes) {
        putchar(ix, iy, *b);
        if (ix > VGA_WIDTH * 2) {
            ix = ix - VGA_WIDTH * 2;
            iy += 1;
        }
        ix += 1;
    }
}
<commit_msg>make 0xb8000 a constant, VGA_ADDRESS<commit_after>use super::core::str::as_bytes;
use super::core::slice::iter;
use super::core::iter::Iterator;
use super::core::option::{Some, None};

static VGA_ADDRESS: uint = 0xb8000;

static VGA_WIDTH  : u16 = 80;
static VGA_HEIGHT : u16 = 24;

static mut curr_x: u16 = 0;
static mut curr_y: u16 = 0;

static mut fg_color: Color = Green;
static mut bg_color: Color = Black;

pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

fn range(lo: uint, hi: uint, it: |uint| ) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

pub fn clear_screen() {
    unsafe {
        range(0, 80*25, |i| {
            *((VGA_ADDRESS + i * 2) as *mut u16) = make_vgaentry(0, fg_color, bg_color);

        });
    }
}

pub fn backspace() {
    unsafe {
        if (curr_x == 0) {
            curr_y -= 1;
            curr_x = VGA_WIDTH - 1;
        } else {
            curr_x -= 1;
        }
        putchar(curr_x, curr_y, 0);
    }
}

pub fn putc(c: u8) {
    unsafe {
        putchar(curr_x, curr_y, c);
        curr_x += 1;
        if (curr_x > VGA_WIDTH) {
            curr_x -= VGA_WIDTH;
            curr_y += 1;
        }
    }
}

pub fn newline() {
    unsafe {
        curr_x = 0;
        curr_y += 1;
    }
}

pub fn putchar(x: u16, y: u16, c: u8) {
    if (x >= VGA_WIDTH || y >= VGA_HEIGHT) {
        return;
    }
    let idx : uint =  (y * VGA_WIDTH * 2 + x * 2) as uint;
    unsafe {
        *((VGA_ADDRESS + idx) as *mut u16) = make_vgaentry(c, fg_color, bg_color);
    }
}

fn make_vgaentry(c: u8, fg: Color, bg: Color) -> u16 {
    let color = fg as u16 | (bg as u16 << 4);
    return c as u16 | (color << 8);
}

pub fn write(x: u16, y: u16, s: &str) {
    let bytes : &[u8] = as_bytes(s);
    let mut ix = x;
    let mut iy = y;
    for b in super::core::slice::iter(bytes) {
        putchar(ix, iy, *b);
        if (ix > VGA_WIDTH * 2) {
            ix = ix - VGA_WIDTH * 2;
            iy += 1;
        }
        ix += 1;
    }
}
<|endoftext|>


<commit_before>use std::libc;
use std::str::raw;

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *libc::c_char) -> *libc::c_char;
}

pub fn version_info() -> ~str {
    let key = "--version";
    let info = key.with_c_str(|c_key| {
        return unsafe { raw::from_c_str(GDALVersionInfo(c_key)) };
    });
    return info;
}

#[test]
fn test_version_info() {
    let rv = version_info();
    assert_eq!(rv.slice(0, 4), "GDAL");
}
<commit_msg>pass argument to version_info<commit_after>use std::libc;
use std::str::raw;

#[link(name = "gdal")]
extern {
    fn GDALVersionInfo(key: *libc::c_char) -> *libc::c_char;
}

pub fn version_info(key: &str) -> ~str {
    let info = key.with_c_str(|c_key| {
        return unsafe { raw::from_c_str(GDALVersionInfo(c_key)) };
    });
    return info;
}

#[test]
fn test_version_info() {
    let release_date = version_info("RELEASE_DATE");
    let release_name = version_info("RELEASE_NAME");
    let version_text = version_info("--version");

    let expected_text: ~str = "GDAL " + release_name + ", " +
        "released " + release_date.slice(0, 4) + "/" +
        release_date.slice(4, 6) + "/" + release_date.slice(6, 8);

    assert_eq!(version_text.into_owned(), expected_text);
}
<|endoftext|>


<commit_before>use std::slice;
use std::ops::{Index, IndexMut};

#[derive(Clone)]
pub struct Grid<T> {
    width: usize,
    height: usize,
    data: Vec<T>,
}

impl<T> Grid<T> {
    /// Construct a new grid filled with a specified element
    #[inline]
    pub fn from_elem(width: usize, height: usize, elem: T) -> Grid<T> where T: Clone {
        Grid {
            width: width,
            height: height,
            data: vec![elem; width * height],
        }
    }

    /// Construct a new grid filled with values specified by a generating function
    #[inline]
    pub fn from_fn<F>(width: usize, height: usize, mut f: F) -> Grid<T>
        where F: FnMut(usize, usize) -> T
    {
        Grid {
            width: width,
            height: height,
            data: (0..(width * height)).map(|i| f(i % width, i / width)).collect(),
        }
    }

    /// Returns the height of the grid
    #[inline]
    pub fn height(&self) -> usize {
        self.height
    }

    /// Returns the width of the grid
    #[inline]
    pub fn width(&self) -> usize {
        self.width
    }

    /// Returns an iterator over references to the elements of the grid in
    /// the order: left-right, up-down
    #[inline]
    pub fn iter(&self) -> slice::Iter<T> {
        self.data.iter()
    }

    /// Returns an iterator over mutable references to the elements of the grid in
    /// the order: left-right, up-down
    #[inline]
    pub fn iter_mut(&mut self) -> slice::IterMut<T> {
        self.data.iter_mut()
    }
}

impl<T> Index<(usize, usize)> for Grid<T> {
    type Output = T;
    fn index(&self, (x, y): (usize, usize)) -> &T {
        assert!(x < self.width && y < self.height);
        &self.data[x + y * self.width]
    }
}

impl<T> IndexMut<(usize, usize)> for Grid<T> {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut T {
        assert!(x < self.width && y < self.height);
        &mut self.data[x + y * self.width]
    }
}
<commit_msg>Add tests and coordinate iterator to Grid struct.<commit_after>use std::slice;
use std::ops::{Index, IndexMut};

#[derive(Clone)]
pub struct Grid<T> {
    width: usize,
    height: usize,
    data: Vec<T>,
}

impl<T> Grid<T> {
    /// Construct a new grid filled with a specified element
    #[inline]
    pub fn from_elem(width: usize, height: usize, elem: T) -> Grid<T> where T: Clone {
        Grid {
            width: width,
            height: height,
            data: vec![elem; width * height],
        }
    }

    /// Construct a new grid filled with values specified by a generating function
    #[inline]
    pub fn from_fn<F>(width: usize, height: usize, mut f: F) -> Grid<T>
        where F: FnMut(usize, usize) -> T
    {
        Grid {
            width: width,
            height: height,
            data: (0..(width * height)).map(|i| f(i % width, i / width)).collect(),
        }
    }

    /// Returns the height of the grid
    #[inline]
    pub fn height(&self) -> usize {
        self.height
    }

    /// Returns the width of the grid
    #[inline]
    pub fn width(&self) -> usize {
        self.width
    }

    /// Returns an iterator over references to the elements of the grid.
    #[inline]
    pub fn iter(&self) -> slice::Iter<T> {
        self.data.iter()
    }

    /// Returns an iterator over mutable references to the elements of the grid.
    #[inline]
    pub fn iter_mut(&mut self) -> slice::IterMut<T> {
        self.data.iter_mut()
    }

	/// Return an iterator over the coordinates of the grid.
	#[inline]
	pub fn coordinates(&self) -> Coordinates {
		Coordinates {
			width: self.width,
			height: self.height,
			x: 0,
			y: 0,
		}
	}
}

impl<T> Index<(usize, usize)> for Grid<T> {
    type Output = T;
    fn index(&self, (x, y): (usize, usize)) -> &T {
        assert!(x < self.width && y < self.height);
        &self.data[x + y * self.width]
    }
}

impl<T> IndexMut<(usize, usize)> for Grid<T> {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut T {
        assert!(x < self.width && y < self.height);
        &mut self.data[x + y * self.width]
    }
}

pub struct Coordinates {
	width: usize,
    height: usize,
	x: usize,
	y: usize,
}

impl Iterator for Coordinates {
	type Item = (usize, usize);

	#[inline]
	fn next(&mut self) -> Option<(usize, usize)> {
		if self.x < self.width {
			self.x += 1;
			Some((self.x - 1, self.y))
		}
		else {
			self.x = 0;
			self.y += 1;

			if self.y < self.height { self.next() } else { None }
		}
	}

	#[inline]
	fn size_hint(&self) -> (usize, Option<usize>) {
		let size = self.width * self.height - self.x - self.width * self.y;
		(size, Some(size))
	}
}

#[cfg(test)]
mod test {
	use super::*;

	#[test]
	fn construction_test() {
		let grid = Grid::from_elem(2, 3, 75_u32);
		assert_eq!(grid.width(), 2);
		assert_eq!(grid.height(), 3);
		assert_eq!(grid.iter().cloned().collect::<Vec<_>>(), vec![75, 75, 75, 75, 75, 75]);
	}

	#[test]
	fn index_test() {
		let mut grid = Grid::from_elem(2, 3, 75_u32);

		grid[(0,0)] = 0;
		grid[(1,0)] = 10;
		grid[(0,1)] = 1;
		grid[(1,1)] = 11;
		grid[(0,2)] = 2;
		grid[(1,2)] = 12;

		assert_eq!(grid.iter().cloned().collect::<Vec<_>>(), vec![0, 10, 1, 11, 2, 12]);
	}

	#[test]
	fn coord_iter_test() {
		let grid = Grid::from_elem(3, 3, 0_u32);
		assert_eq!(grid.coordinates().collect::<Vec<_>>(),
			vec![(0,0), (1,0), (2,0), (0,1), (1,1), (2,1), (0,2), (1,2), (2,2)]);
	}
}
<|endoftext|>


<commit_before>use std::fmt;
use Command;

#[deriving(PartialEq, Eq, PartialOrd, Ord)]
pub struct Grid {
    width: u32,
    height: u32,
    chars: Vec<char>,
}

impl fmt::Show for Grid {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        let s: String = String::from_chars(self.chars.as_slice());
        write!(w, "Grid {{ width: {}, height: {}, chars: {} }}",
               self.width, self.height, s)
    }
}

#[deriving(PartialEq, Eq, PartialOrd, Ord)]
pub enum ParseErr {
    PrematureLineEnd(u32, String, u32),
    BadTerminationChar(u32, String, char),
}

impl fmt::Show for ParseErr {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            PrematureLineEnd(h, ref s, width) =>
                write!(w, "line {} content {} ended prematurely; \
                           expected {} characters", h, s, width),
            BadTerminationChar(h, ref s, c) =>
                write!(w, "line {} expected end of input or line \
                           after {}, got {}", h, s, c),
        }
    }
}

impl Grid {
    pub fn new(width: u32, height: u32, background: char) -> Grid {
        let len = width * height;
        let chars = Vec::from_elem(len.to_uint().unwrap(), background);
        Grid { width: width, height: height, chars: chars }
    }

    pub fn to_string(&self) -> String {
        let len = self.height * (self.width + 1);
        let mut s = String::with_capacity(len.to_uint().unwrap());
        for y in range(0, self.height) {
            for x in range(0, self.width) {
                s.push(self.get(x, y));
            }
            s.push('\n');
        }
        s
    }

    pub fn from_str(s: &str) -> Result<Grid, ParseErr> {
        let mut w = 0u32;
        for c in s.chars() {
            if c == '\n' {
                break;
            } else {
                w += 1;
            }
        }

        let mut grid = vec![];
        let mut chars = s.chars();
        let mut h = 0;

        loop {
            let mut started_line = false;
            let row_start = grid.len();
            for i in range(0, w) {
                match (i, chars.next()) {
                    (0, None) => break,
                    (_, None) => {
                        let line = String::from_chars(grid.slice_from(row_start));
                        return Err(PrematureLineEnd(h, line, w))
                    }
                    (_, Some(c)) => {
                        if !started_line {
                            h += 1;
                            started_line = true;
                        }
                        grid.push(c)
                    }
                }
            }
            match chars.next() {
                None => break,
                Some('\n') => continue,
                Some(c) => {
                    let line = String::from_chars(grid.slice_from(row_start));
                    return Err(BadTerminationChar(h, line, c))
                }
            }
        }

        Ok(Grid { width: w, height: h, chars: grid })
    }

    pub fn width(&self) -> u32 { self.width }
    pub fn height(&self) -> u32 { self.height }

    pub fn get(&self, x: u32, y: u32) -> char {
        assert!(x < self.width);
        assert!(y < self.height);
        let idx = y * self.width + x;
        self.chars[idx.to_uint().unwrap()]
    }

    pub fn set(&mut self, x: u32, y: u32, c: char) {
        assert!(x < self.width);
        assert!(y < self.height);
        let idx = y * self.width + x;
        self.chars[idx.to_uint().unwrap()] = c;
    }

    pub fn exec(&mut self, command: &Command) {
        let Command { x, y, w, h, fill } = *command;

        if w == 1 || h == 1 {
            return self.draw_line(command);
        }

        self.set(x, y, '+');
        self.set(x, y+h-1, '+');
        self.set(x+w-1, y, '+');
        self.set(x+w-1, y+h-1, '+');

        for i in range(x + 1, x + w - 1) {
            self.set(i, y, '-');
            self.set(i, y + h - 1, '-');
        }

        for j in range(y + 1, y + h - 1) {
            self.set(x, j, '|');
            self.set(x + w - 1, j, '|');
        }

        for i in range(x+1, x + w - 1) {
            for j in range(y + 1, y + h - 1) {
                self.set(i, j, fill);
            }
        }
    }

    fn draw_line(&mut self, command: &Command) {
        assert!(command.w == 1 || command.h == 1);
        let Command { x, y, w, h, fill } = *command;
        for i in range(x, x+w) {
            for j in range(y, y+h) {
                self.set(i, j, fill);
            }
        }
    }
}

#[test]
fn simple_parse() {
    assert_eq!(Grid::from_str("...").unwrap(),
               Grid {width: 3, height: 1, chars: "...".chars().collect() });
    assert_eq!(Grid::from_str("...\n").unwrap(),
               Grid {width: 3, height: 1, chars: "...".chars().collect() });
    assert_eq!(Grid::from_str("...\n...\n").unwrap(),
               Grid {width: 3, height: 2, chars: "......".chars().collect() });
    assert_eq!(Grid::from_str("...\n...").unwrap(),
               Grid {width: 3, height: 2, chars: "......".chars().collect() });
    assert_eq!(Grid::from_str("abc\ndef\n").unwrap(),
               Grid {width: 3, height: 2, chars: "abcdef".chars().collect() });
}

#[test]
fn premature_line_end() {
    assert_eq!(Grid::from_str("abc\nd"),
               Err(PrematureLineEnd(2, "d".to_string(), 3)));
}

#[test]
fn unexpected_terminator() {
    assert_eq!(Grid::from_str("abc\ndefg"),
               Err(BadTerminationChar(2, "def".to_string(), 'g')))
}
<commit_msg>bugfix for v0.12<commit_after>use std::fmt;
use Command;

#[deriving(PartialEq, Eq, PartialOrd, Ord)]
pub struct Grid {
    width: u32,
    height: u32,
    chars: Vec<char>,
}

impl fmt::Show for Grid {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        let s: String = String::from_chars(self.chars.as_slice());
        write!(w, "Grid {{ width: {}, height: {}, chars: {} }}",
               self.width, self.height, s)
    }
}

#[deriving(PartialEq, Eq, PartialOrd, Ord)]
pub enum ParseErr {
    PrematureLineEnd(u32, String, u32),
    BadTerminationChar(u32, String, char),
}

impl fmt::Show for ParseErr {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            PrematureLineEnd(h, ref s, width) =>
                write!(w, "line {} content {} ended prematurely; \
                           expected {} characters", h, s, width),
            BadTerminationChar(h, ref s, c) =>
                write!(w, "line {} expected end of input or line \
                           after {}, got {}", h, s, c),
        }
    }
}

impl Grid {
    pub fn new(width: u32, height: u32, background: char) -> Grid {
        let len = width * height;
        let chars = Vec::from_elem(len.to_uint().unwrap(), background);
        Grid { width: width, height: height, chars: chars }
    }

    pub fn to_string(&self) -> String {
        let len = self.height * (self.width + 1);
        let mut s = String::with_capacity(len.to_uint().unwrap());
        for y in range(0, self.height) {
            for x in range(0, self.width) {
                s.push(self.get(x, y));
            }
            s.push('\n');
        }
        s
    }

    pub fn from_str(s: &str) -> Result<Grid, ParseErr> {
        let mut w = 0u32;
        for c in s.chars() {
            if c == '\n' {
                break;
            } else {
                w += 1;
            }
        }

        let mut grid = vec![];
        let mut chars = s.chars();
        let mut h = 0;

        loop {
            let mut started_line = false;
            let row_start = grid.len();
            for i in range(0, w) {
                match (i, chars.next()) {
                    (0, None) => break,
                    (_, None) => {
                        let line = String::from_chars(grid.slice_from(row_start));
                        return Err(PrematureLineEnd(h, line, w))
                    }
                    (_, Some(c)) => {
                        if !started_line {
                            h += 1;
                            started_line = true;
                        }
                        grid.push(c)
                    }
                }
            }
            match chars.next() {
                None => break,
                Some('\n') => continue,
                Some(c) => {
                    let line = String::from_chars(grid.slice_from(row_start));
                    return Err(BadTerminationChar(h, line, c))
                }
            }
        }

        Ok(Grid { width: w, height: h, chars: grid })
    }

    pub fn width(&self) -> u32 { self.width }
    pub fn height(&self) -> u32 { self.height }

    pub fn get(&self, x: u32, y: u32) -> char {
        assert!(x < self.width);
        assert!(y < self.height);
        let idx = y * self.width + x;
        self.chars[idx.to_uint().unwrap()]
    }

    pub fn set(&mut self, x: u32, y: u32, c: char) {
        assert!(x < self.width);
        assert!(y < self.height);
        let idx = y * self.width + x;
        *self.chars.get_mut(idx.to_uint().unwrap()) = c;
    }

    pub fn exec(&mut self, command: &Command) {
        let Command { x, y, w, h, fill } = *command;

        if w == 1 || h == 1 {
            return self.draw_line(command);
        }

        self.set(x, y, '+');
        self.set(x, y+h-1, '+');
        self.set(x+w-1, y, '+');
        self.set(x+w-1, y+h-1, '+');

        for i in range(x + 1, x + w - 1) {
            self.set(i, y, '-');
            self.set(i, y + h - 1, '-');
        }

        for j in range(y + 1, y + h - 1) {
            self.set(x, j, '|');
            self.set(x + w - 1, j, '|');
        }

        for i in range(x+1, x + w - 1) {
            for j in range(y + 1, y + h - 1) {
                self.set(i, j, fill);
            }
        }
    }

    fn draw_line(&mut self, command: &Command) {
        assert!(command.w == 1 || command.h == 1);
        let Command { x, y, w, h, fill } = *command;
        for i in range(x, x+w) {
            for j in range(y, y+h) {
                self.set(i, j, fill);
            }
        }
    }
}

#[test]
fn simple_parse() {
    assert_eq!(Grid::from_str("...").unwrap(),
               Grid {width: 3, height: 1, chars: "...".chars().collect() });
    assert_eq!(Grid::from_str("...\n").unwrap(),
               Grid {width: 3, height: 1, chars: "...".chars().collect() });
    assert_eq!(Grid::from_str("...\n...\n").unwrap(),
               Grid {width: 3, height: 2, chars: "......".chars().collect() });
    assert_eq!(Grid::from_str("...\n...").unwrap(),
               Grid {width: 3, height: 2, chars: "......".chars().collect() });
    assert_eq!(Grid::from_str("abc\ndef\n").unwrap(),
               Grid {width: 3, height: 2, chars: "abcdef".chars().collect() });
}

#[test]
fn premature_line_end() {
    assert_eq!(Grid::from_str("abc\nd"),
               Err(PrematureLineEnd(2, "d".to_string(), 3)));
}

#[test]
fn unexpected_terminator() {
    assert_eq!(Grid::from_str("abc\ndefg"),
               Err(BadTerminationChar(2, "def".to_string(), 'g')))
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::str;

use repo_config::*;

use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha1::Sha1;

use rustc_serialize::hex::ToHex;
use rustc_serialize::json::*;

#[derive(Debug)]
pub struct GithubHook {
    pub event: String,
    pub payload: String,
    pub signature: String,
    pub config_root: String
}

impl GithubHook {
    pub fn new(event: &str, payload: &str, signature: &str, config_root: &str) -> GithubHook {
        GithubHook {
            event: event.to_string(),
            payload: payload.to_string(),
            signature: signature.to_string(),
            config_root: config_root.to_string()
        }
    }

    pub fn receive(&self) {
        let json_payload = Json::from_str(&self.payload).unwrap();
        let repo_name = unwrap_json_string(json_payload.find_path(&["repository", "full_name"]));

        info!("Received {} for {}", self.event, repo_name);

        let repo_config_filename = self.config_root.clone() + "/" + &str::replace(&repo_name, "/", "__") + ".json";
        let repo_config = RepoConfig::new(repo_config_filename);

        match self.is_valid(repo_config.secret) {
            false => {
                error!("Payload validation failed, aborting!");
                panic!();
            },
            true => info!("Payload validation succeeded.")
        };

        let event = self.event.as_ref();
        if repo_config.handlers.contains_key(event) {
            let handler = repo_config.handlers.get(event).unwrap();
            match event {
                "push" => {
                    let push_ref = unwrap_json_string(json_payload.find("ref"));
                    for aref in &repo_config.refs {
                        if aref == &push_ref {
                            let mut command = Command::new(handler);

                            let head = unwrap_json_string(json_payload.find_path(&["head_commit", "id"]));
                            command.env("HEAD", head);

                            self.execute_handler(&mut command);
                            break;
                        }
                    }
                },
                "pull_request" => {
                    let mut command = Command::new(handler);

                    command.env("ACTION", unwrap_json_string(json_payload.find("action")));

                    let pr_number = unwrap_json_number(json_payload.find_path(&["pull_request", "number"]));
                    command.env("PR", pr_number.to_string());

                    self.execute_handler(&mut command);
                },
                _ => {
                    let mut command = Command::new(handler);
                    self.execute_handler(&mut command);
                }
            };
        }
    }

    fn is_valid(&self, secret: Option<String>) -> bool {
        match secret {
            None => {
                info!("No secret in config file, skipping validation.");
                true
            },
            Some(secret) => {
                let mut hmac = Hmac::new(Sha1::new(), &secret.as_bytes());
                hmac.input(&self.payload.as_bytes()[..]);

                str::replace(&self.signature, "sha1=", "") == hmac.result().code().to_hex()
            }
        }
    }

    fn execute_handler(&self, handler: &mut Command) {
        match handler.status() {
            Ok(_) => info!("Command ran successfully."),
            Err(exception) => error!("Command failed: {}", exception)
        }
    }
}

fn unwrap_json_string(json: Option<&Json>) -> String {
    json.unwrap().as_string().unwrap().to_string()
}

fn unwrap_json_number(json: Option<&Json>) -> i64 {
    json.unwrap().as_i64().unwrap()
}
<commit_msg>Reduce code nesting<commit_after>use std::process::Command;
use std::str;

use repo_config::*;

use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha1::Sha1;

use rustc_serialize::hex::ToHex;
use rustc_serialize::json::*;

#[derive(Debug)]
pub struct GithubHook {
    pub event: String,
    pub payload: String,
    pub signature: String,
    pub config_root: String
}

impl GithubHook {
    pub fn new(event: &str, payload: &str, signature: &str, config_root: &str) -> GithubHook {
        GithubHook {
            event: event.to_string(),
            payload: payload.to_string(),
            signature: signature.to_string(),
            config_root: config_root.to_string()
        }
    }

    pub fn receive(&self) {
        let json_payload = Json::from_str(&self.payload).unwrap();
        let repo_name = unwrap_json_string(json_payload.find_path(&["repository", "full_name"]));

        info!("Received {} for {}", self.event, repo_name);

        let repo_config_filename = self.config_root.clone() + "/" + &str::replace(&repo_name, "/", "__") + ".json";
        let repo_config = RepoConfig::new(repo_config_filename);

        match self.is_valid(repo_config.secret.as_ref()) {
            false => {
                error!("Payload validation failed, aborting!");
                panic!();
            },
            true => info!("Payload validation succeeded.")
        };

        let event = self.event.as_ref();
        if repo_config.handlers.contains_key(event) {
            let handler = repo_config.handlers.get(event).unwrap();
            match event {
                "push" => self.process_push(json_payload, &repo_config, handler),
                "pull_request" => self.process_pull_request(json_payload, handler),
                _ => self.process_default(handler)
            };
        }
    }

    fn is_valid(&self, secret: Option<&String>) -> bool {
        match secret {
            None => {
                info!("No secret in config file, skipping validation.");
                true
            },
            Some(secret) => {
                let mut hmac = Hmac::new(Sha1::new(), &secret.as_bytes());
                hmac.input(&self.payload.as_bytes()[..]);

                str::replace(&self.signature, "sha1=", "") == hmac.result().code().to_hex()
            }
        }
    }

    fn process_push(&self, json_payload: Json, repo_config: &RepoConfig, handler: &String) {
        let push_ref = unwrap_json_string(json_payload.find("ref"));
        let refs = &repo_config.refs;
        for aref in refs {
            if aref == &push_ref {
                let mut command = Command::new(handler);

                let head = unwrap_json_string(json_payload.find_path(&["head_commit", "id"]));
                command.env("HEAD", head);

                self.execute_handler(&mut command);
                break;
            }
        }
    }

    fn process_pull_request(&self, json_payload: Json, handler: &String) {
        let mut command = Command::new(handler);

        command.env("ACTION", unwrap_json_string(json_payload.find("action")));

        let pr_number = unwrap_json_number(json_payload.find_path(&["pull_request", "number"]));
        command.env("PR", pr_number.to_string());

        self.execute_handler(&mut command);
    }

    fn process_default(&self, handler: &String) {
        let mut command = Command::new(handler);
        self.execute_handler(&mut command);
    }

    fn execute_handler(&self, handler: &mut Command) {
        match handler.status() {
            Ok(_) => info!("Command ran successfully."),
            Err(exception) => error!("Command failed: {}", exception)
        }
    }
}

fn unwrap_json_string(json: Option<&Json>) -> String {
    json.unwrap().as_string().unwrap().to_string()
}

fn unwrap_json_number(json: Option<&Json>) -> i64 {
    json.unwrap().as_i64().unwrap()
}
<|endoftext|>


<commit_before>
use std::io::{Read, SeekFrom};
use std::cmp;

use hyper;
use hyper::Error;
use hyper::client::Client;
use hyper::client::response::Response;
use hyper::header::ByteRangeSpec;
use hyper::header::ByteRangeSpec::FromTo;
use hyper::header::Range::Bytes;
use hyper::header::{ContentLength, ContentRange, ContentRangeSpec};

use reader::ReaderKind;
use reader::Reader;
use buffer::Buffer;

#[derive(Debug)]
pub struct HttpReader {
  position: u64,
  size: Option<u64>,
  buf: Buffer
}

impl HttpReader {
  fn create(content_length: Option<u64>) -> HttpReader {
    HttpReader{
      position: 0,
      size: content_length,
      buf: Buffer::create()
    }
  }
}

pub fn exists(filename: &String) -> bool {
  let client = Client::new();
  match client.head(filename).send() {
    Ok(resp) => resp.status == hyper::Ok,
    Err(_) => false
  }
}

fn get_head(filename: &String) -> Result<Response, Error> {
  let client = Client::new();
  client.head(filename).send()
}

fn get_content_length(response: &Response) -> Option<u64> {
  match response.headers.get::<ContentLength>() {
    Some(length) => Some(**length as u64),
    None => None
  }
}

fn get_content_range(response: &Response) -> Result<Option<u64>, String> {
  match response.headers.get::<ContentRange>() {
    Some(content_range) => {
      match content_range.clone() {
        ContentRange(ContentRangeSpec::Bytes{
            range: _range,
            instance_length: length
          }) => {
          Ok(length)
        },
        ContentRange(ContentRangeSpec::Unregistered{unit: _unit, resp: _resp}) => {
          Err("Unregistered, actually unsupported".to_string())
        }
      }
    },
    None =>
      Err("Missing content_range".to_string()),
  }
}

pub fn open(filename: &String) -> Result<Reader, String> {
  match get_head(filename) {
    Err(error) => Err(error.to_string()),
    Ok(response) => {

      let content_length = get_content_length(&response);
      let http_reader = HttpReader::create(content_length);

      let reader = Reader{
        filename: filename.to_string(),
        mode: ReaderKind::Http,
        file: None,
        cache_size: None,
        http_reader: Some(http_reader)
      };

      Ok(reader)
    }
  }
}

fn get_data_range(position: u64, size: usize) -> Vec<ByteRangeSpec> {
  let start = position;
  let end = position + (size - 1) as u64;

  vec![FromTo(start, end)]
}

fn load_data(reader: &mut Reader, size: usize) -> Result<Option<Vec<u8>>, String> {

  info!("make HTTP request with request {:?} bytes", size);
  match reader.http_reader {
    None => Err("missing HTTP reader".to_string()),
    Some(ref mut http_reader) => {

      match http_reader.size {
          Some(size) => {
            if http_reader.position >= size {
              return Ok(None)
            }
          },
          None => (),
      };

      let range = get_data_range(http_reader.position, size);

      let client = Client::new();
      let request =
        client
        .get(&reader.filename)
        .header(Bytes(range));

      let mut response = try!(request.send().map_err(|e| e.to_string()));

      let mut loaded_size : u64 = 0;
      {
        match get_content_length(&response) {
            Some(content_length) => loaded_size = content_length,
            None => return Err("Missing content_length".to_string()),
        }

        match get_content_range(&response) {
          Ok(length) => http_reader.size = length,
          Err(msg) => return Err(msg),
        }
      }

      match loaded_size {
        0 => Err("Bad request range".to_string()),
        _ => {
          let mut body = vec![0; loaded_size as usize];
          try!(Read::read_exact(&mut response, &mut body).map_err(|e| e.to_string()));

          http_reader.position = http_reader.position + loaded_size as u64;
          Ok(Some(body))
        }
      }
    }
  }
}

fn define_size_to_load(reader: &Reader, cache_size: usize, size: usize) -> Option<usize> {
  match reader.http_reader {
    Some(ref http_reader) => {
      match http_reader.buf.get_cached_size() < size {
        true => Some(cmp::max(cache_size, size)),
        _ => None
      }
    },
    None => panic!("Missing Http Reader"),
  }
}

pub fn read(mut reader: &mut Reader, size: usize) -> Result<Vec<u8>, String> {
  debug!("read {:?} bytes", size);
  match reader.cache_size {
    None => {
      match load_data(reader, size) {
        Ok(optional_data) => {
          match optional_data {
            Some(data) => Ok(data),
            None => Ok(Vec::new()),
          }
        },
        Err(msg) => return Err(msg)
      }
    },
    Some(cache_size) => {
      let mut buffer = Vec::new();
      match define_size_to_load(reader, cache_size, size) {
        Some(required_size) => {
          match load_data(&mut reader, required_size) {
            Ok(optional_data) => {
              match optional_data {
                Some(full_data) => {
                  match reader.http_reader {
                    Some(ref mut http_reader) => {
                      http_reader.buf.append_data(&full_data);
                      buffer = http_reader.buf.get_data(size);
                    },
                    None => panic!("Missing Http Reader"),
                  }
                },
                None => {
                  return Ok(Vec::new())
                },
              }
            },
            Err(msg) => {
              return Err(msg)
            }
          }
        },
        None => {
          match reader.http_reader {
            Some(ref mut http_reader) => {
              buffer = http_reader.buf.get_data(size);
            },
            None => return Err("Missing Http Reader".to_string()),
          };
        },
      }
      Ok(buffer)
    }
  }
}

pub fn get_position(reader: &Reader) -> Result<u64, String> {
  match reader.http_reader {
    Some(ref http_reader) => Ok(http_reader.position),
    None => Err("missing HTTP reader".to_string()),
  }
}

pub fn get_size(reader: &mut Reader) -> Result<u64, String> {

  let _data = read(reader, 1);

  match reader.http_reader {
      Some(ref mut http_reader) => {
        match http_reader.size {
            Some(length) => Ok(length),
            None => Err("missing HTTP header".to_string()),
        }
      },
      None => Err("missing HTTP reader".to_string()),
  }
}

pub fn seek(mut reader: &mut Reader, seek: SeekFrom) -> Result<u64, String> {
  // println!("Seek");

  let mut require_reset_buffer : bool = false;
  let mut position : u64 = 0;

  match reader.http_reader {
    Some(ref mut http_reader) => {
      match seek {
        SeekFrom::Start(value) => {
          require_reset_buffer = true;
          http_reader.position = value;
          position = http_reader.position
        },
        SeekFrom::End(value) => {
          require_reset_buffer = true;
          http_reader.position = value as u64;
          position = http_reader.position
        },
        SeekFrom::Current(value) => {
          // println!("position {:?}", http_reader.position);
          let mut new_position = http_reader.position;
          // new_position -= http_reader.buffer.len() as u64;
          new_position += value as u64;

          // println!("new {:?} > {:?} + {:?}", new_position, http_reader.position, http_reader.buf.get_cached_size());

          if new_position > http_reader.position + http_reader.buf.get_cached_size() as u64 {
            require_reset_buffer = true;
            http_reader.position = new_position - http_reader.buf.get_cached_size() as u64;
            // println!("new position == {:?}", http_reader.position);
            position = http_reader.position
          } else {
            // println!("split_off {:?} at {:?}", http_reader.buf.get_cached_size(), value as usize);
            let _seek_data = http_reader.buf.get_data(value as usize);
          }
        }
      }
    },
    None => return Err("missing HTTP reader".to_string()),
  }

  if require_reset_buffer == true {
    match reset_buffer(reader) {
      Ok(_) => {},
      Err(msg) => return Err(msg)
    }
  }

  Ok(position)
}

fn reset_buffer(reader: &mut Reader) -> Result<(), String> {
  match reader.http_reader {
    Some(ref mut http_reader) => {
      http_reader.buf.reset();
      Ok(())
    },
    None => Err("missing HTTP reader".to_string()),
  }
}
<commit_msg>fix get position when HTTP use buffering<commit_after>
use std::io::{Read, SeekFrom};
use std::cmp;

use hyper;
use hyper::Error;
use hyper::client::Client;
use hyper::client::response::Response;
use hyper::header::ByteRangeSpec;
use hyper::header::ByteRangeSpec::FromTo;
use hyper::header::Range::Bytes;
use hyper::header::{ContentLength, ContentRange, ContentRangeSpec};

use reader::ReaderKind;
use reader::Reader;
use buffer::Buffer;

#[derive(Debug)]
pub struct HttpReader {
  position: u64,
  size: Option<u64>,
  buf: Buffer
}

impl HttpReader {
  fn create(content_length: Option<u64>) -> HttpReader {
    HttpReader{
      position: 0,
      size: content_length,
      buf: Buffer::create()
    }
  }
}

pub fn exists(filename: &String) -> bool {
  let client = Client::new();
  match client.head(filename).send() {
    Ok(resp) => resp.status == hyper::Ok,
    Err(_) => false
  }
}

fn get_head(filename: &String) -> Result<Response, Error> {
  let client = Client::new();
  client.head(filename).send()
}

fn get_content_length(response: &Response) -> Option<u64> {
  match response.headers.get::<ContentLength>() {
    Some(length) => Some(**length as u64),
    None => None
  }
}

fn get_content_range(response: &Response) -> Result<Option<u64>, String> {
  match response.headers.get::<ContentRange>() {
    Some(content_range) => {
      match content_range.clone() {
        ContentRange(ContentRangeSpec::Bytes{
            range: _range,
            instance_length: length
          }) => {
          Ok(length)
        },
        ContentRange(ContentRangeSpec::Unregistered{unit: _unit, resp: _resp}) => {
          Err("Unregistered, actually unsupported".to_string())
        }
      }
    },
    None =>
      Err("Missing content_range".to_string()),
  }
}

pub fn open(filename: &String) -> Result<Reader, String> {
  match get_head(filename) {
    Err(error) => Err(error.to_string()),
    Ok(response) => {

      let content_length = get_content_length(&response);
      let http_reader = HttpReader::create(content_length);

      let reader = Reader{
        filename: filename.to_string(),
        mode: ReaderKind::Http,
        file: None,
        cache_size: None,
        http_reader: Some(http_reader)
      };

      Ok(reader)
    }
  }
}

fn get_data_range(position: u64, size: usize) -> Vec<ByteRangeSpec> {
  let start = position;
  let end = position + (size - 1) as u64;

  vec![FromTo(start, end)]
}

fn load_data(reader: &mut Reader, size: usize) -> Result<Option<Vec<u8>>, String> {

  info!("make HTTP request with request {:?} bytes", size);
  match reader.http_reader {
    None => Err("missing HTTP reader".to_string()),
    Some(ref mut http_reader) => {

      match http_reader.size {
          Some(size) => {
            if http_reader.position >= size {
              return Ok(None)
            }
          },
          None => (),
      };

      let range = get_data_range(http_reader.position, size);

      let client = Client::new();
      let request =
        client
        .get(&reader.filename)
        .header(Bytes(range));

      let mut response = try!(request.send().map_err(|e| e.to_string()));

      let mut loaded_size : u64 = 0;
      {
        match get_content_length(&response) {
            Some(content_length) => loaded_size = content_length,
            None => return Err("Missing content_length".to_string()),
        }

        match get_content_range(&response) {
          Ok(length) => http_reader.size = length,
          Err(msg) => return Err(msg),
        }
      }

      match loaded_size {
        0 => Err("Bad request range".to_string()),
        _ => {
          let mut body = vec![0; loaded_size as usize];
          try!(Read::read_exact(&mut response, &mut body).map_err(|e| e.to_string()));

          http_reader.position = http_reader.position + loaded_size as u64;
          Ok(Some(body))
        }
      }
    }
  }
}

fn define_size_to_load(reader: &Reader, cache_size: usize, size: usize) -> Option<usize> {
  match reader.http_reader {
    Some(ref http_reader) => {
      match http_reader.buf.get_cached_size() < size {
        true => Some(cmp::max(cache_size, size)),
        _ => None
      }
    },
    None => panic!("Missing Http Reader"),
  }
}

pub fn read(mut reader: &mut Reader, size: usize) -> Result<Vec<u8>, String> {
  debug!("read {:?} bytes", size);
  match reader.cache_size {
    None => {
      match load_data(reader, size) {
        Ok(optional_data) => {
          match optional_data {
            Some(data) => Ok(data),
            None => Ok(Vec::new()),
          }
        },
        Err(msg) => return Err(msg)
      }
    },
    Some(cache_size) => {
      let mut buffer = Vec::new();
      match define_size_to_load(reader, cache_size, size) {
        Some(required_size) => {
          match load_data(&mut reader, required_size) {
            Ok(optional_data) => {
              match optional_data {
                Some(full_data) => {
                  match reader.http_reader {
                    Some(ref mut http_reader) => {
                      http_reader.buf.append_data(&full_data);
                      buffer = http_reader.buf.get_data(size);
                    },
                    None => panic!("Missing Http Reader"),
                  }
                },
                None => {
                  return Ok(Vec::new())
                },
              }
            },
            Err(msg) => {
              return Err(msg)
            }
          }
        },
        None => {
          match reader.http_reader {
            Some(ref mut http_reader) => {
              buffer = http_reader.buf.get_data(size);
            },
            None => return Err("Missing Http Reader".to_string()),
          };
        },
      }
      Ok(buffer)
    }
  }
}

pub fn get_position(reader: &Reader) -> Result<u64, String> {

  match reader.cache_size {
    None => {
      match reader.http_reader {
        Some(ref http_reader) => {
          Ok(http_reader.position)
        },
        None => Err("missing HTTP reader".to_string()),
      }
    },
    Some(_cache_size) => {
      match reader.http_reader {
        Some(ref http_reader) => {
          Ok(http_reader.position - http_reader.buf.get_cached_size() as u64)
        },
        None => Err("missing HTTP reader".to_string()),
      }
    }
  }
}

pub fn get_size(reader: &mut Reader) -> Result<u64, String> {

  let _data = read(reader, 1);

  match reader.http_reader {
      Some(ref mut http_reader) => {
        match http_reader.size {
            Some(length) => Ok(length),
            None => Err("missing HTTP header".to_string()),
        }
      },
      None => Err("missing HTTP reader".to_string()),
  }
}

pub fn seek(mut reader: &mut Reader, seek: SeekFrom) -> Result<u64, String> {
  // println!("Seek");

  let mut require_reset_buffer : bool = false;
  let mut position : u64 = 0;

  match reader.http_reader {
    Some(ref mut http_reader) => {
      match seek {
        SeekFrom::Start(value) => {
          require_reset_buffer = true;
          http_reader.position = value;
          position = http_reader.position
        },
        SeekFrom::End(value) => {
          require_reset_buffer = true;
          http_reader.position = value as u64;
          position = http_reader.position
        },
        SeekFrom::Current(value) => {
          // println!("position {:?}", http_reader.position);
          let mut new_position = http_reader.position;
          // new_position -= http_reader.buffer.len() as u64;
          new_position += value as u64;

          // println!("new {:?} > {:?} + {:?}", new_position, http_reader.position, http_reader.buf.get_cached_size());

          if new_position > http_reader.position + http_reader.buf.get_cached_size() as u64 {
            require_reset_buffer = true;
            http_reader.position = new_position - http_reader.buf.get_cached_size() as u64;
            // println!("new position == {:?}", http_reader.position);
            position = http_reader.position
          } else {
            // println!("split_off {:?} at {:?}", http_reader.buf.get_cached_size(), value as usize);
            let _seek_data = http_reader.buf.get_data(value as usize);
          }
        }
      }
    },
    None => return Err("missing HTTP reader".to_string()),
  }

  if require_reset_buffer == true {
    match reset_buffer(reader) {
      Ok(_) => {},
      Err(msg) => return Err(msg)
    }
  }

  Ok(position)
}

fn reset_buffer(reader: &mut Reader) -> Result<(), String> {
  match reader.http_reader {
    Some(ref mut http_reader) => {
      http_reader.buf.reset();
      Ok(())
    },
    None => Err("missing HTTP reader".to_string()),
  }
}
<|endoftext|>


<commit_before>use crate::CONFIG;
use failure::Error;
use reqwest::{self, Client, StatusCode};
use serde_json::Value;
use std::time::Duration;

lazy_static! {
    static ref CLIENT: Client = Client::builder()
        .timeout(match CONFIG.read().timeout {
            Some(timeout) => Some(Duration::from_secs(timeout)),
            None => None,
        })
        .build()
        .expect("Failed to create HTTP client!");
}

pub fn request(path: &str, request_body: Option<Value>) -> Result<String, Error> {
    let mut request_builder = CLIENT.post(&format!("{}{}", CONFIG.read().base_url, path));

    if let Some(json) = request_body {
        debug!("Request body: {:?}", json);
        request_builder = request_builder.json(&json);
    } else {
        debug!("Empty request body...");
    }

    let mut response = request_builder.send()?;
    match response.status() {
        StatusCode::OK => Ok(response.text()?),
        s => Err(format_err!("Request failed with status code {}", s)),
    }
}

#[cfg(test)]
mod tests {

    use super::request;
    use crate::{Settings, CONFIG};
    use serde_json::{self, Value};
    use std::env;
    use test_server::{self, helper, HttpResponse};

    #[test]
    fn request_with_body_is_content_type_json() {
        let server = test_server::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());
        init_config();

        let _ = request("", Some(json!({ "body": helper::random_string(100) })));
        let request = server.requests.next().unwrap();

        assert_eq!(
            Some(&String::from("application/json")),
            request.headers.get("content-type")
        );

        env::remove_var("K2_BASE_URL");
    }

    #[test]
    fn send_request_body_if_given() {
        let server = test_server::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());
        init_config();

        let body = json!({ "body": helper::random_string(100) });

        let _ = request("", Some(body.clone()));
        let request = server.requests.next().unwrap();
        let json: Value = serde_json::from_str(&request.body).unwrap();

        assert_eq!(body, json);

        env::remove_var("K2_BASE_URL");
    }

    #[test]
    fn if_no_json_is_given_send_empty_request_body() {
        let server = test_server::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());
        init_config();

        let _ = request("", None);
        let request = server.requests.next().unwrap();

        assert!(request.body.is_empty());

        env::remove_var("K2_BASE_URL");
    }

    fn init_config() {
        let mut config_guard = CONFIG.write();
        *config_guard = Settings::init().unwrap();
        drop(config_guard);
    }
}
<commit_msg>add debug log for request url<commit_after>use crate::CONFIG;
use failure::Error;
use reqwest::{self, Client, StatusCode};
use serde_json::Value;
use std::time::Duration;

lazy_static! {
    static ref CLIENT: Client = Client::builder()
        .timeout(match CONFIG.read().timeout {
            Some(timeout) => Some(Duration::from_secs(timeout)),
            None => None,
        })
        .build()
        .expect("Failed to create HTTP client!");
}

pub fn request(path: &str, request_body: Option<Value>) -> Result<String, Error> {
    let url = format!("{}{}", CONFIG.read().base_url, path);
    debug!("Request URL: {}", url);
    let mut request_builder = CLIENT.post(&url);

    if let Some(json) = request_body {
        debug!("Request body: {:?}", json);
        request_builder = request_builder.json(&json);
    } else {
        debug!("Empty request body...");
    }

    let mut response = request_builder.send()?;
    match response.status() {
        StatusCode::OK => Ok(response.text()?),
        s => Err(format_err!("Request failed with status code {}", s)),
    }
}

#[cfg(test)]
mod tests {

    use super::request;
    use crate::{Settings, CONFIG};
    use serde_json::{self, Value};
    use std::env;
    use test_server::{self, helper, HttpResponse};

    #[test]
    fn request_with_body_is_content_type_json() {
        let server = test_server::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());
        init_config();

        let _ = request("", Some(json!({ "body": helper::random_string(100) })));
        let request = server.requests.next().unwrap();

        assert_eq!(
            Some(&String::from("application/json")),
            request.headers.get("content-type")
        );

        env::remove_var("K2_BASE_URL");
    }

    #[test]
    fn send_request_body_if_given() {
        let server = test_server::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());
        init_config();

        let body = json!({ "body": helper::random_string(100) });

        let _ = request("", Some(body.clone()));
        let request = server.requests.next().unwrap();
        let json: Value = serde_json::from_str(&request.body).unwrap();

        assert_eq!(body, json);

        env::remove_var("K2_BASE_URL");
    }

    #[test]
    fn if_no_json_is_given_send_empty_request_body() {
        let server = test_server::new(0, |_| HttpResponse::BadRequest().into());
        env::set_var("K2_BASE_URL", server.url());
        init_config();

        let _ = request("", None);
        let request = server.requests.next().unwrap();

        assert!(request.body.is_empty());

        env::remove_var("K2_BASE_URL");
    }

    fn init_config() {
        let mut config_guard = CONFIG.write();
        *config_guard = Settings::init().unwrap();
        drop(config_guard);
    }
}
<|endoftext|>


<commit_before>//! Contains the HTTP server component.

use std::collections::HashMap;
use std::env;
use std::fs;
use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::thread;

use porthole;
use nickel::{Nickel, StaticFilesHandler};

use markdown;

/// The HTTP server.
///
/// The server listens on the provided port, rendering the markdown preview when a GET request is
/// received at the server root.
pub struct Server {
    local_addr: SocketAddr,

    /// The "current working directory" of the server. Any static file requests will be joined to
    /// this directory.
    cwd: Arc<Mutex<PathBuf>>,
}

impl Server {
    /// Creates a new server that listens on socket address `addr`.
    pub fn new<A, P>(addr: A, working_directory: P) -> Server
        where A: ToSocketAddrs,
              P: AsRef<Path>
    {
        let socket_addr = addr.to_socket_addrs()
                              .unwrap()
                              .map(|addr| {
                                  if addr.port() == 0 {
                                      let unused_port = porthole::open().unwrap();
                                      format!("localhost:{}", unused_port)
                                          .to_socket_addrs()
                                          .unwrap()
                                          .next()
                                          .unwrap()
                                  } else {
                                      addr
                                  }
                              })
                              .next()
                              .unwrap();

        Server {
            local_addr: socket_addr,
            cwd: Arc::new(Mutex::new(working_directory.as_ref().to_owned())),
        }
    }

    pub fn change_working_directory<P>(&mut self, dir: P)
        where P: AsRef<Path>
    {
        let mut cwd = self.cwd.lock().unwrap();
        *cwd = dir.as_ref().to_owned();
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        Ok(self.local_addr)
    }

    fn listen_forever(local_addr: SocketAddr,
                      websocket_port: u16,
                      config: &::Config,
                      current_working_directory: Arc<Mutex<PathBuf>>) {
        let mut server = Nickel::new();

        let mut data = HashMap::new();
        data.insert("websocket_port", websocket_port.to_string());

        data.insert("initial_markdown", markdown::to_html(&config.initial_markdown));
        data.insert("highlight_theme", config.highlight_theme.to_owned());
        data.insert("custom_css", config.custom_css.to_owned());

        // We need to figure out the crate root, so we can pass absolute paths into the nickel
        // APIs.
        let root = {
            let crate_root = Path::new(file!()).parent().unwrap().parent().unwrap();
            if crate_root.is_absolute() {
                crate_root.to_owned()
            } else {
                let mut current_dir = env::current_dir().unwrap();
                current_dir.push(crate_root);
                current_dir.to_owned()
            }
        };

        let mut markdown_view = root.to_path_buf();
        markdown_view.push("templates/markdown_view.html");

        server.utilize(router! {
            get "/" => |_, response| {
                return response.render(markdown_view.to_str().unwrap(), &data);
            }
        });

        let local_cwd = current_working_directory.clone();
        server.utilize(middleware! { |request, response|
            let path = request.path_without_query().map(|path| {
                path[1..].to_owned()
            });

            if let Some(path) = path {
                let path = local_cwd.lock().unwrap().clone().join(path);
                match fs::metadata(&path) {
                    Ok(ref attr) if attr.is_file() => return response.send_file(&path),
                    Err(ref e) if e.kind() != io::ErrorKind::NotFound => {
                        debug!("Error getting metadata for file '{:?}': {:?}",
                                                                  path, e)
                    }
                    _ => {}
                }
            };
        });

        let mut static_dir = root.to_path_buf();
        static_dir.push("static");
        assert!(static_dir.is_absolute());
        server.utilize(StaticFilesHandler::new(static_dir.to_str().unwrap()));

        server.listen(local_addr);
    }

    /// Starts the server.
    ///
    /// Once a connection is received, the client will initiate WebSocket connections on
    /// `websocket_port`. If `initial_markdown` is present, it will be displayed on the first
    /// connection.
    pub fn start(&self, websocket_port: u16, config: &::Config) {
        let current_working_directory = self.cwd.clone();
        let local_addr = self.local_addr;
        let config = config.clone();
        thread::spawn(move || {
            Self::listen_forever(local_addr,
                                 websocket_port,
                                 &config,
                                 current_working_directory);
        });
    }
}
<commit_msg>replace crate root location logic with macro<commit_after>//! Contains the HTTP server component.

use std::collections::HashMap;
use std::fs;
use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::thread;

use porthole;
use nickel::{Nickel, StaticFilesHandler};

use markdown;

/// The HTTP server.
///
/// The server listens on the provided port, rendering the markdown preview when a GET request is
/// received at the server root.
pub struct Server {
    local_addr: SocketAddr,

    /// The "current working directory" of the server. Any static file requests will be joined to
    /// this directory.
    cwd: Arc<Mutex<PathBuf>>,
}

impl Server {
    /// Creates a new server that listens on socket address `addr`.
    pub fn new<A, P>(addr: A, working_directory: P) -> Server
        where A: ToSocketAddrs,
              P: AsRef<Path>
    {
        let socket_addr = addr.to_socket_addrs()
                              .unwrap()
                              .map(|addr| {
                                  if addr.port() == 0 {
                                      let unused_port = porthole::open().unwrap();
                                      format!("localhost:{}", unused_port)
                                          .to_socket_addrs()
                                          .unwrap()
                                          .next()
                                          .unwrap()
                                  } else {
                                      addr
                                  }
                              })
                              .next()
                              .unwrap();

        Server {
            local_addr: socket_addr,
            cwd: Arc::new(Mutex::new(working_directory.as_ref().to_owned())),
        }
    }

    pub fn change_working_directory<P>(&mut self, dir: P)
        where P: AsRef<Path>
    {
        let mut cwd = self.cwd.lock().unwrap();
        *cwd = dir.as_ref().to_owned();
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        Ok(self.local_addr)
    }

    fn listen_forever(local_addr: SocketAddr,
                      websocket_port: u16,
                      config: &::Config,
                      current_working_directory: Arc<Mutex<PathBuf>>) {
        let mut server = Nickel::new();

        let mut data = HashMap::new();
        data.insert("websocket_port", websocket_port.to_string());

        data.insert("initial_markdown", markdown::to_html(&config.initial_markdown));
        data.insert("highlight_theme", config.highlight_theme.to_owned());
        data.insert("custom_css", config.custom_css.to_owned());

        let root = Path::new(env!("CARGO_MANIFEST_DIR"));

        let mut markdown_view = root.to_path_buf();
        markdown_view.push("templates/markdown_view.html");

        server.utilize(router! {
            get "/" => |_, response| {
                return response.render(markdown_view.to_str().unwrap(), &data);
            }
        });

        let local_cwd = current_working_directory.clone();
        server.utilize(middleware! { |request, response|
            let path = request.path_without_query().map(|path| {
                path[1..].to_owned()
            });

            if let Some(path) = path {
                let path = local_cwd.lock().unwrap().clone().join(path);
                match fs::metadata(&path) {
                    Ok(ref attr) if attr.is_file() => return response.send_file(&path),
                    Err(ref e) if e.kind() != io::ErrorKind::NotFound => {
                        debug!("Error getting metadata for file '{:?}': {:?}",
                                                                  path, e)
                    }
                    _ => {}
                }
            };
        });

        let mut static_dir = root.to_path_buf();
        static_dir.push("static");
        assert!(static_dir.is_absolute());
        server.utilize(StaticFilesHandler::new(static_dir.to_str().unwrap()));

        server.listen(local_addr);
    }

    /// Starts the server.
    ///
    /// Once a connection is received, the client will initiate WebSocket connections on
    /// `websocket_port`. If `initial_markdown` is present, it will be displayed on the first
    /// connection.
    pub fn start(&self, websocket_port: u16, config: &::Config) {
        let current_working_directory = self.cwd.clone();
        let local_addr = self.local_addr;
        let config = config.clone();
        thread::spawn(move || {
            Self::listen_forever(local_addr,
                                 websocket_port,
                                 &config,
                                 current_working_directory);
        });
    }
}
<|endoftext|>