<commit_before>use super::model::*;

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

/// Known state composed from received events.
#[derive(Debug, Clone)]
pub struct State {
	user: CurrentUser,
	settings: UserSettings,
	server_settings: Vec<UserServerSettings>,
	session_id: String,
	private_channels: Vec<PrivateChannel>,
	servers: Vec<LiveServer>,
}

impl State {
	/// Create a new state from an initial `ReadyEvent`.
	pub fn new(ready: ReadyEvent) -> State {
		if ready.version != VERSION {
			warn!("Got protocol version {} instead of {}", ready.version, VERSION);
		}
		State {
			user: ready.user,
			settings: ready.user_settings,
			server_settings: ready.user_server_settings,
			session_id: ready.session_id,
			private_channels: ready.private_channels,
			servers: ready.servers,
		}
	}

	/// Update the state according to the changes described in the given event.
	pub fn update(&mut self, event: &Event) {
		match *event {
			Event::Ready(ref ready) => *self = State::new(ready.clone()),
			Event::GatewayChanged(_, ref ready) => *self = State::new(ready.clone()),
			Event::UserUpdate(ref user) => self.user = user.clone(),
			Event::UserSettingsUpdate {
				ref enable_tts_command, ref inline_attachment_media,
				ref inline_embed_media, ref locale,
				ref message_display_compact, ref muted_channels,
				ref render_embeds, ref show_current_game,
				ref theme, ref convert_emoticons,
			} => {
				opt_modify(&mut self.settings.enable_tts_command, enable_tts_command);
				opt_modify(&mut self.settings.inline_attachment_media, inline_attachment_media);
				opt_modify(&mut self.settings.inline_embed_media, inline_embed_media);
				opt_modify(&mut self.settings.locale, locale);
				opt_modify(&mut self.settings.message_display_compact, message_display_compact);
				opt_modify(&mut self.settings.muted_channels, muted_channels);
				opt_modify(&mut self.settings.render_embeds, render_embeds);
				opt_modify(&mut self.settings.show_current_game, show_current_game);
				opt_modify(&mut self.settings.theme, theme);
				opt_modify(&mut self.settings.convert_emoticons, convert_emoticons);
			}
			Event::UserServerSettingsUpdate(ref settings) => {
				self.server_settings.iter_mut().find(|s| s.server_id == settings.server_id).map(|srv| {
					srv.clone_from(settings);
				});
			}
			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.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);
					srv.verification_level = server.verification_level;
				});
			}
			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);
					});
				}
			},
			_ => {}
		}
	}

	/// Get information about the logged-in user.
	#[inline]
	pub fn user(&self) -> &CurrentUser { &self.user }

	/// Get the logged-in user's client settings.
	#[inline]
	pub fn settings(&self) -> &UserSettings { &self.settings }

	/// Get the websocket session ID.
	#[inline]
	pub fn session_id(&self) -> &str { &self.session_id }

	/// Get the list of private channels with other users.
	#[inline]
	pub fn private_channels(&self) -> &[PrivateChannel] { &self.private_channels }

	/// Get the list of servers this user has access to.
	#[inline]
	pub fn servers(&self) -> &[LiveServer] { &self.servers }

	/// Look up a private or public channel by its ID.
	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
#[derive(Debug, Clone, Copy)]
pub enum ChannelRef<'a> {
	/// A private channel
	Private(&'a PrivateChannel),
	/// A public channel and its server
	Public(&'a LiveServer, &'a PublicChannel),
}

#[inline]
fn opt_modify<T: Clone>(dest: &mut T, src: &Option<T>) {
	if let Some(val) = src.as_ref() {
		dest.clone_from(val);
	}
}
<commit_msg>Update member_count when members are added or removed<commit_after>use super::model::*;

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

/// Known state composed from received events.
#[derive(Debug, Clone)]
pub struct State {
	user: CurrentUser,
	settings: UserSettings,
	server_settings: Vec<UserServerSettings>,
	session_id: String,
	private_channels: Vec<PrivateChannel>,
	servers: Vec<LiveServer>,
}

impl State {
	/// Create a new state from an initial `ReadyEvent`.
	pub fn new(ready: ReadyEvent) -> State {
		if ready.version != VERSION {
			warn!("Got protocol version {} instead of {}", ready.version, VERSION);
		}
		State {
			user: ready.user,
			settings: ready.user_settings,
			server_settings: ready.user_server_settings,
			session_id: ready.session_id,
			private_channels: ready.private_channels,
			servers: ready.servers,
		}
	}

	/// Update the state according to the changes described in the given event.
	pub fn update(&mut self, event: &Event) {
		match *event {
			Event::Ready(ref ready) => *self = State::new(ready.clone()),
			Event::GatewayChanged(_, ref ready) => *self = State::new(ready.clone()),
			Event::UserUpdate(ref user) => self.user = user.clone(),
			Event::UserSettingsUpdate {
				ref enable_tts_command, ref inline_attachment_media,
				ref inline_embed_media, ref locale,
				ref message_display_compact, ref muted_channels,
				ref render_embeds, ref show_current_game,
				ref theme, ref convert_emoticons,
			} => {
				opt_modify(&mut self.settings.enable_tts_command, enable_tts_command);
				opt_modify(&mut self.settings.inline_attachment_media, inline_attachment_media);
				opt_modify(&mut self.settings.inline_embed_media, inline_embed_media);
				opt_modify(&mut self.settings.locale, locale);
				opt_modify(&mut self.settings.message_display_compact, message_display_compact);
				opt_modify(&mut self.settings.muted_channels, muted_channels);
				opt_modify(&mut self.settings.render_embeds, render_embeds);
				opt_modify(&mut self.settings.show_current_game, show_current_game);
				opt_modify(&mut self.settings.theme, theme);
				opt_modify(&mut self.settings.convert_emoticons, convert_emoticons);
			}
			Event::UserServerSettingsUpdate(ref settings) => {
				self.server_settings.iter_mut().find(|s| s.server_id == settings.server_id).map(|srv| {
					srv.clone_from(settings);
				});
			}
			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.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);
					srv.verification_level = server.verification_level;
				});
			}
			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.member_count += 1;
					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.member_count -= 1;
					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);
					});
				}
			},
			_ => {}
		}
	}

	/// Get information about the logged-in user.
	#[inline]
	pub fn user(&self) -> &CurrentUser { &self.user }

	/// Get the logged-in user's client settings.
	#[inline]
	pub fn settings(&self) -> &UserSettings { &self.settings }

	/// Get the websocket session ID.
	#[inline]
	pub fn session_id(&self) -> &str { &self.session_id }

	/// Get the list of private channels with other users.
	#[inline]
	pub fn private_channels(&self) -> &[PrivateChannel] { &self.private_channels }

	/// Get the list of servers this user has access to.
	#[inline]
	pub fn servers(&self) -> &[LiveServer] { &self.servers }

	/// Look up a private or public channel by its ID.
	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
#[derive(Debug, Clone, Copy)]
pub enum ChannelRef<'a> {
	/// A private channel
	Private(&'a PrivateChannel),
	/// A public channel and its server
	Public(&'a LiveServer, &'a PublicChannel),
}

#[inline]
fn opt_modify<T: Clone>(dest: &mut T, src: &Option<T>) {
	if let Some(val) = src.as_ref() {
		dest.clone_from(val);
	}
}
<|endoftext|>


<commit_before>//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

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

use std::io::Cursor;
use super::*;
extern crate test_assembler;
use self::test_assembler::*;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
    Auto,
}

fn make_box_raw<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    let mut section = Section::new();
    let box_size = Label::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
        BoxSize::Auto => section.B32(&box_size),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) => {
            if size > 0 {
                assert_eq!(size as u64, section.size())
            }
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        BoxSize::Auto => {
            assert!(section.size() <= u32::max_value() as u64,
              "Tried to use a long box with BoxSize::Auto");
            box_size.set_const(section.size());
        },
        // Skip checking BoxSize::Unchecked* cases.
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_box<F>(size: u32, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, func)
}

fn make_fullbox<F>(size: BoxSize, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(size, name, |s| {
        func(s.B8(version)
              .B8(0)
              .B8(0)
              .B8(0))
    })
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box_raw(BoxSize::Short(8), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 8);
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box_raw(BoxSize::Long(16), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 16);
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box_raw(BoxSize::Short(0), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::Unsupported) => (),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedShort(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedLong(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(24, b"ftyp", |s| {
        s.append_bytes(b"mp42")
         .B32(0) // minor version
         .append_bytes(b"isom")
         .append_bytes(b"mp42")
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"ftyp"));
    assert_eq!(parsed.header.size, 24);
    assert_eq!(parsed.major_brand, FourCC(*b"mp42"));
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], FourCC(*b"isom"));
    assert_eq!(parsed.compatible_brands[1], FourCC(*b"mp42"));
}

#[test]
#[should_panic(expected = "expected an error result")]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box_raw(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0) // minor version
            .append_bytes(b"isom")
    });
    let mut context = MediaContext::new();
    match read_mp4(&mut stream, &mut context) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => assert!(false, "expected an error result"),
        _ => assert!(false, "expected a different error result"),
    }
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(BoxSize::Auto, b"elst", 0, |s| {
        s.B32(1) // list count
          // first entry
         .B32(1234) // duration
         .B32(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 28);
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(BoxSize::Auto, b"elst", 1, |s| {
        s.B32(2) // list count
         // first entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
         // second entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 56);
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 44);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(::std::u32::MAX) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mdhd(&mut stream, &header, &mut super::Track::new(0));
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 120);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mvhd(&mut stream, &header);
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(BoxSize::Auto, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(::std::u32::MAX)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_vpcc() {
    let data_length = 12u16;
    let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 0, |s| {
        s.B8(2)
         .B8(0)
         .B8(0x82)
         .B8(0)
         .B16(data_length)
         .append_repeated(42, data_length as usize)
    });
    let header = read_box_header(&mut stream).unwrap();
    assert_eq!(header.name.as_bytes(), b"vpcC");
    let r = super::read_vpcc(&mut stream);
    assert!(r.is_ok());
}
<commit_msg>Go back to fixed sizes for older tests.<commit_after>//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

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

use std::io::Cursor;
use super::*;
extern crate test_assembler;
use self::test_assembler::*;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
    Auto,
}

fn make_box_raw<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    let mut section = Section::new();
    let box_size = Label::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
        BoxSize::Auto => section.B32(&box_size),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) => {
            if size > 0 {
                assert_eq!(size as u64, section.size())
            }
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        BoxSize::Auto => {
            assert!(section.size() <= u32::max_value() as u64,
              "Tried to use a long box with BoxSize::Auto");
            box_size.set_const(section.size());
        },
        // Skip checking BoxSize::Unchecked* cases.
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_box<F>(size: u32, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, func)
}

fn make_fullbox<F>(size: BoxSize, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(size, name, |s| {
        func(s.B8(version)
              .B8(0)
              .B8(0)
              .B8(0))
    })
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box_raw(BoxSize::Short(8), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 8);
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box_raw(BoxSize::Long(16), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 16);
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box_raw(BoxSize::Short(0), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::Unsupported) => (),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedShort(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedLong(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(24, b"ftyp", |s| {
        s.append_bytes(b"mp42")
         .B32(0) // minor version
         .append_bytes(b"isom")
         .append_bytes(b"mp42")
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"ftyp"));
    assert_eq!(parsed.header.size, 24);
    assert_eq!(parsed.major_brand, FourCC(*b"mp42"));
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], FourCC(*b"isom"));
    assert_eq!(parsed.compatible_brands[1], FourCC(*b"mp42"));
}

#[test]
#[should_panic(expected = "expected an error result")]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box_raw(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0) // minor version
            .append_bytes(b"isom")
    });
    let mut context = MediaContext::new();
    match read_mp4(&mut stream, &mut context) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => assert!(false, "expected an error result"),
        _ => assert!(false, "expected a different error result"),
    }
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(BoxSize::Short(28), b"elst", 0, |s| {
        s.B32(1) // list count
          // first entry
         .B32(1234) // duration
         .B32(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 28);
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(BoxSize::Short(56), b"elst", 1, |s| {
        s.B32(2) // list count
         // first entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
         // second entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 56);
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(BoxSize::Short(44), b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 44);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(::std::u32::MAX) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(BoxSize::Short(44), b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mdhd(&mut stream, &header, &mut super::Track::new(0));
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(BoxSize::Short(108), b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(BoxSize::Short(120), b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 120);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(BoxSize::Short(120), b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mvhd(&mut stream, &header);
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(BoxSize::Short(108), b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(::std::u32::MAX)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_vpcc() {
    let data_length = 12u16;
    let mut stream = make_fullbox(BoxSize::Auto, b"vpcC", 0, |s| {
        s.B8(2)
         .B8(0)
         .B8(0x82)
         .B8(0)
         .B16(data_length)
         .append_repeated(42, data_length as usize)
    });
    let header = read_box_header(&mut stream).unwrap();
    assert_eq!(header.name.as_bytes(), b"vpcC");
    let r = super::read_vpcc(&mut stream);
    assert!(r.is_ok());
}
<|endoftext|>


<commit_before>use std::fmt;
use std::borrow::Cow;

use attr::AttributeList;
use escape::Escaped;

#[derive(Clone, Debug, PartialEq, Eq)]
/// An HTML token. By convention, `Token::Text` should be preferred over
/// `Token::RawText` when a piece of text can be represented by both. For
/// instance, use `Token::Text` when tokenizing whitespaces or line-breaks, but
/// use `Token::RawText` for representing all text inside `<style>` tag.
///
/// When `Display`ing a `Token`, the output stream is assumed to be Unicode, and
/// therefore only five characters are escaped: `&`, `<`, `>`, `"`, and `'`
/// ([ref](http://stackoverflow.com/a/7382028)).
pub enum Token<'a> {
    StartTag {
        name: Cow<'a, str>,
        attrs: AttributeList<'a>,
        /// Marker indicating self-closing tags such as `<br />`
        self_closing: bool,
    },
    EndTag {
        name: Cow<'a, str>,
    },
    /// The text contained will be escaped on `Display`.
    Text(Cow<'a, str>),
    /// The text contained will be `Display`ed as-is.
    RawText(Cow<'a, str>),
    /// Comments contained within `<!--` and `-->`. No validation is done to
    /// ensure that the text does not contain `-->`.
    Comment(Cow<'a, str>),
    /// The HTML5 DOCTYPE declaration
    DOCTYPE,
}

impl<'a> Token<'a> {
    pub fn start_tag<S>(name: S, attrs: AttributeList<'a>) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::StartTag {
            name: name.into(),
            attrs: attrs,
            self_closing: false,
        }
    }

    pub fn end_tag<S>(name: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::EndTag { name: name.into() }
    }

    pub fn text<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::Text(s.into())
    }

    pub fn raw_text<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::RawText(s.into())
    }

    pub fn comment<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::Comment(s.into())
    }

    /// If `self` is a `StartTag`, returns the `Token` after setting
    /// `self_closing` to `true`; otherwise, it is a no-op.
    pub fn closed(self) -> Token<'a> {
        if let Token::StartTag { name, attrs, .. } = self {
            Token::StartTag {
                name: name,
                attrs: attrs,
                self_closing: true,
            }
        } else {
            self
        }
    }
}

impl<'a> fmt::Display for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Token::StartTag { ref name, ref attrs, self_closing } => {
                try!(write!(f, "<{}", name));
                for attr in attrs.iter() {
                    try!(write!(f, " {}", attr));
                }
                if self_closing {
                    write!(f, " />")
                } else {
                    write!(f, ">")
                }
            }
            Token::EndTag { ref name } => write!(f, "</{}>", name),
            Token::Text(ref text) => write!(f, "{}", Escaped(text)),
            Token::RawText(ref text) => write!(f, "{}", text),
            Token::Comment(ref text) => write!(f, "<!--{}-->", text),
            Token::DOCTYPE => write!(f, "<!DOCTYPE html>"),
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn token_variants() {
        use Token;
        use attr::AttributeList;

        let start_tag = Token::start_tag("tag", AttributeList::empty());
        assert_eq!(format!("{}", start_tag), "<tag>");

        let end_tag = Token::end_tag("tag");
        assert_eq!(format!("{}", end_tag), "</tag>");

        let text = Token::text("<bomb>");
        assert_eq!(format!("{}", text), "<bomb>");

        let raw_text = Token::raw_text("<bomb>");
        assert_eq!(format!("{}", raw_text), "<bomb>");

        let comment = Token::comment("Multi\nline\ncomment");
        assert_eq!(format!("{}", comment), "<!--Multi\nline\ncomment-->");

        assert_eq!(format!("{}", Token::DOCTYPE), "<!DOCTYPE html>");
    }
}
<commit_msg>Add documentation to token variants and fields<commit_after>use std::fmt;
use std::borrow::Cow;

use attr::AttributeList;
use escape::Escaped;

#[derive(Clone, Debug, PartialEq, Eq)]
/// An HTML token, these are representations of everything needed to generate
/// an [HTML document](https://www.w3.org/TR/html/syntax.html#writing).
///
/// By convention, [`Token::Text`](#variant.Text) should be preferred over
/// [`Token::RawText`](#variant.RawText) when a piece of text can be
/// represented by both. For instance, use `Text` when tokenizing whitespaces
/// or line-breaks, but use `RawText` for representing all text inside
/// a `<style>` tag.
///
/// When `Display`ing a `Token`, the output stream is assumed to be Unicode, and
/// therefore only five characters are escaped: `&`, `<`, `>`, `"`, and `'`
/// ([ref](http://stackoverflow.com/a/7382028)).
pub enum Token<'a> {
    /// A [start tag](https://www.w3.org/TR/html/syntax.html#syntax-start-tag)
    /// token.
    StartTag {
        /// The element's [tag
        /// name](https://www.w3.org/TR/html/syntax.html#syntax-tag-name).
        name: Cow<'a, str>,

        /// Any attributes for the start tag.
        attrs: AttributeList<'a>,

        /// Marker indicating the tag should be self-closing, such as `<br />`
        /// (although `br` is a [void
        /// element](https://www.w3.org/TR/html/syntax.html#void-elements) so
        /// this has no effect on it).
        self_closing: bool,
    },

    /// An [end tag](https://www.w3.org/TR/html/syntax.html#syntax-end-tag)
    /// token.
    EndTag {
        /// The element's [tag
        /// name](https://www.w3.org/TR/html/syntax.html#syntax-tag-name).
        name: Cow<'a, str>,
    },

    /// The text contained will be escaped on `Display`.
    Text(Cow<'a, str>),

    /// The text contained will be `Display`ed as-is.
    RawText(Cow<'a, str>),

    /// Comments contained within `<!--` and `-->`. No validation is done to
    /// ensure that the text conforms to the [html comment
    /// syntax](https://www.w3.org/TR/html/syntax.html#syntax-comments).
    Comment(Cow<'a, str>),

    /// The [HTML5 DOCTYPE
    /// declaration](https://www.w3.org/TR/html/syntax.html#syntax-doctype)
    /// (`<!DOCTYPE html>`)
    DOCTYPE,
}

impl<'a> Token<'a> {
    pub fn start_tag<S>(name: S, attrs: AttributeList<'a>) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::StartTag {
            name: name.into(),
            attrs: attrs,
            self_closing: false,
        }
    }

    pub fn end_tag<S>(name: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::EndTag { name: name.into() }
    }

    pub fn text<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::Text(s.into())
    }

    pub fn raw_text<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::RawText(s.into())
    }

    pub fn comment<S>(s: S) -> Token<'a>
        where S: Into<Cow<'a, str>>
    {
        Token::Comment(s.into())
    }

    /// If `self` is a `StartTag`, returns the `Token` after setting
    /// `self_closing` to `true`; otherwise, it is a no-op.
    pub fn closed(self) -> Token<'a> {
        if let Token::StartTag { name, attrs, .. } = self {
            Token::StartTag {
                name: name,
                attrs: attrs,
                self_closing: true,
            }
        } else {
            self
        }
    }
}

impl<'a> fmt::Display for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Token::StartTag { ref name, ref attrs, self_closing } => {
                try!(write!(f, "<{}", name));
                for attr in attrs.iter() {
                    try!(write!(f, " {}", attr));
                }
                if self_closing {
                    write!(f, " />")
                } else {
                    write!(f, ">")
                }
            }
            Token::EndTag { ref name } => write!(f, "</{}>", name),
            Token::Text(ref text) => write!(f, "{}", Escaped(text)),
            Token::RawText(ref text) => write!(f, "{}", text),
            Token::Comment(ref text) => write!(f, "<!--{}-->", text),
            Token::DOCTYPE => write!(f, "<!DOCTYPE html>"),
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn token_variants() {
        use Token;
        use attr::AttributeList;

        let start_tag = Token::start_tag("tag", AttributeList::empty());
        assert_eq!(format!("{}", start_tag), "<tag>");

        let end_tag = Token::end_tag("tag");
        assert_eq!(format!("{}", end_tag), "</tag>");

        let text = Token::text("<bomb>");
        assert_eq!(format!("{}", text), "<bomb>");

        let raw_text = Token::raw_text("<bomb>");
        assert_eq!(format!("{}", raw_text), "<bomb>");

        let comment = Token::comment("Multi\nline\ncomment");
        assert_eq!(format!("{}", comment), "<!--Multi\nline\ncomment-->");

        assert_eq!(format!("{}", Token::DOCTYPE), "<!DOCTYPE html>");
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_tr"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 * (c) kwantam <kwantam@gmail.com>
 *     20150428 created `expand` module to eliminate most allocs during setup
 * (c) Sergey "Shnatsel" Davidoff <shnatsel@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate bit_set;
extern crate getopts;
extern crate fnv;

#[macro_use]
extern crate uucore;

use bit_set::BitSet;
use getopts::Options;
use std::io::{stdin, stdout, BufRead, BufWriter, Write};
use fnv::FnvHashMap;

use expand::ExpandSet;

mod expand;

static NAME: &'static str = "tr";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BUFFER_LEN: usize = 1024;

fn delete(set: ExpandSet, complement: bool) {
    let mut bset = BitSet::new();
    let stdin = stdin();
    let mut locked_stdin = stdin.lock();
    let mut buffered_stdout = BufWriter::new(stdout());
    let mut buf = String::with_capacity(BUFFER_LEN + 4);
    let mut char_output_buffer: [u8; 4] = [0;4];

    for c in set {
        bset.insert(c as usize);
    }

    let is_allowed = |c : char| {
        if complement {
            bset.contains(c as usize)
        } else {
            !bset.contains(c as usize)
        }
    };

    while let Ok(length) = locked_stdin.read_line(&mut buf) {
        if length == 0 { break }
        { // isolation to make borrow checker happy
            let filtered = buf.chars().filter(|c| is_allowed(*c));
            for c in filtered {
                let char_as_bytes = c.encode_utf8(&mut char_output_buffer);
                buffered_stdout.write_all(char_as_bytes.as_bytes()).unwrap();
            }
        }
        buf.clear();
    }
}

fn tr<'a>(set1: ExpandSet<'a>, mut set2: ExpandSet<'a>) {
    let mut map = FnvHashMap::default();
    let stdin = stdin();
    let mut locked_stdin = stdin.lock();
    let mut buffered_stdout = BufWriter::new(stdout());
    let mut buf = String::with_capacity(BUFFER_LEN + 4);
    let mut char_output_buffer: [u8; 4] = [0;4];

    let mut s2_prev = '_';
    for i in set1 {
        s2_prev = set2.next().unwrap_or(s2_prev);

        map.insert(i as usize, s2_prev);
    }

    while let Ok(length) = locked_stdin.read_line(&mut buf) {
        if length == 0 { break }

        { // isolation to make borrow checker happy
            let output_stream = buf.chars().map(|c| *map.get(&(c as usize)).unwrap_or(&c));
            for c in output_stream {
                let char_as_bytes = c.encode_utf8(&mut char_output_buffer);
                buffered_stdout.write_all(char_as_bytes.as_bytes()).unwrap();
            }
        }

        buf.clear();
    }
}

fn usage(opts: &Options) {
    println!("{} {}", NAME, VERSION);
    println!("");
    println!("Usage:");
    println!("  {} [OPTIONS] SET1 [SET2]", NAME);
    println!("");
    println!("{}", opts.usage("Translate or delete characters."));
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("c", "complement", "use the complement of SET1");
    opts.optflag("C", "", "same as -c");
    opts.optflag("d", "delete", "delete characters in SET1");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(err) => {
            show_error!("{}", err);
            return 1;
        }
    };

    if matches.opt_present("help") {
        usage(&opts);
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.free.is_empty() {
        usage(&opts);
        return 1;
    }

    let dflag = matches.opt_present("d");
    let cflag = matches.opts_present(&["c".to_owned(), "C".to_owned()]);
    let sets = matches.free;

    if cflag && !dflag {
        show_error!("-c is only supported with -d");
        return 1;
    }

    if dflag {
        let set1 = ExpandSet::new(sets[0].as_ref());
        delete(set1, cflag);
    } else {
        let set1 = ExpandSet::new(sets[0].as_ref());
        let set2 = ExpandSet::new(sets[1].as_ref());
        tr(set1, set2);
    }

    0
}
<commit_msg>tr: use as_bytes on whole output string<commit_after>#![crate_name = "uu_tr"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 * (c) kwantam <kwantam@gmail.com>
 *     20150428 created `expand` module to eliminate most allocs during setup
 * (c) Sergey "Shnatsel" Davidoff <shnatsel@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate bit_set;
extern crate getopts;
extern crate fnv;

#[macro_use]
extern crate uucore;

use bit_set::BitSet;
use getopts::Options;
use std::io::{stdin, stdout, BufRead, BufWriter, Write};
use fnv::FnvHashMap;

use expand::ExpandSet;

mod expand;

static NAME: &'static str = "tr";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BUFFER_LEN: usize = 1024;

fn delete(set: ExpandSet, complement: bool) {
    let mut bset = BitSet::new();
    let stdin = stdin();
    let mut locked_stdin = stdin.lock();
    let mut buffered_stdout = BufWriter::new(stdout());
    let mut buf = String::with_capacity(BUFFER_LEN + 4);
    let mut char_output_buffer: [u8; 4] = [0;4];

    for c in set {
        bset.insert(c as usize);
    }

    let is_allowed = |c : char| {
        if complement {
            bset.contains(c as usize)
        } else {
            !bset.contains(c as usize)
        }
    };

    while let Ok(length) = locked_stdin.read_line(&mut buf) {
        if length == 0 { break }
        { // isolation to make borrow checker happy
            let filtered = buf.chars().filter(|c| is_allowed(*c));
            for c in filtered {
                let char_as_bytes = c.encode_utf8(&mut char_output_buffer);
                buffered_stdout.write_all(char_as_bytes.as_bytes()).unwrap();
            }
        }
        buf.clear();
    }
}

fn tr<'a>(set1: ExpandSet<'a>, mut set2: ExpandSet<'a>) {
    let mut map = FnvHashMap::default();
    let stdin = stdin();
    let mut locked_stdin = stdin.lock();
    let mut buffered_stdout = BufWriter::new(stdout());
    let mut buf = String::with_capacity(BUFFER_LEN + 4);
    let mut output_buf = String::with_capacity(BUFFER_LEN + 4);

    let mut s2_prev = '_';
    for i in set1 {
        s2_prev = set2.next().unwrap_or(s2_prev);

        map.insert(i as usize, s2_prev);
    }

    while let Ok(length) = locked_stdin.read_line(&mut buf) {
        if length == 0 { break }

        { // isolation to make borrow checker happy
            let output_stream = buf.chars().map(|c| *map.get(&(c as usize)).unwrap_or(&c));
            output_buf.extend(output_stream);
            buffered_stdout.write_all(output_buf.as_bytes()).unwrap();
        }

        buf.clear();
        output_buf.clear();
    }
}

fn usage(opts: &Options) {
    println!("{} {}", NAME, VERSION);
    println!("");
    println!("Usage:");
    println!("  {} [OPTIONS] SET1 [SET2]", NAME);
    println!("");
    println!("{}", opts.usage("Translate or delete characters."));
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = Options::new();

    opts.optflag("c", "complement", "use the complement of SET1");
    opts.optflag("C", "", "same as -c");
    opts.optflag("d", "delete", "delete characters in SET1");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(err) => {
            show_error!("{}", err);
            return 1;
        }
    };

    if matches.opt_present("help") {
        usage(&opts);
        return 0;
    }

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.free.is_empty() {
        usage(&opts);
        return 1;
    }

    let dflag = matches.opt_present("d");
    let cflag = matches.opts_present(&["c".to_owned(), "C".to_owned()]);
    let sets = matches.free;

    if cflag && !dflag {
        show_error!("-c is only supported with -d");
        return 1;
    }

    if dflag {
        let set1 = ExpandSet::new(sets[0].as_ref());
        delete(set1, cflag);
    } else {
        let set1 = ExpandSet::new(sets[0].as_ref());
        let set2 = ExpandSet::new(sets[1].as_ref());
        tr(set1, set2);
    }

    0
}
<|endoftext|>


<commit_before>//! Define all public custom types here.

use std::ops::Deref;
use std::convert::From;

/// Represents a sequence number in a WAL file.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct SequenceNumber(pub u64);

impl From<u64> for SequenceNumber {
    fn from(x: u64) -> SequenceNumber {
        SequenceNumber(x)
    }
}

impl From<SequenceNumber> for u64 {
    fn from(SequenceNumber(x): SequenceNumber) -> u64 {
        x
    }
}

impl Deref for SequenceNumber {
    type Target = u64;

    fn deref(&self) -> &u64 {
        &self.0
    }
}
<commit_msg>feat(types): add FullKey impl<commit_after>//! Define all public custom types here.

use std::convert::From;
use std::mem;
use std::ops::Deref;
use std::str;

/// Represents a sequence number in a WAL file.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct SequenceNumber(pub u64);

/// 0 is always committed
pub const MIN_UNCOMMITTED_SEQ: SequenceNumber = SequenceNumber(1);

impl ::std::fmt::Display for SequenceNumber {
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl From<u64> for SequenceNumber {
    fn from(x: u64) -> SequenceNumber {
        SequenceNumber(x)
    }
}

impl From<SequenceNumber> for u64 {
    fn from(SequenceNumber(x): SequenceNumber) -> u64 {
        x
    }
}

impl Deref for SequenceNumber {
    type Target = u64;

    fn deref(&self) -> &u64 {
        &self.0
    }
}

/// User-oriented representation of internal key types.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum EntryType {
    Put = 0x1,
    Delete = 0x0,
    SingleDelete = 0x7,
    Merge = 0x2,
    RangeDeletion = 0xf,
    BlobIndex = 0x11,
    Other,
}

impl EntryType {
    pub fn from_u8(val: u8) -> EntryType {
        use EntryType::*;

        match val {
            0x1 => Put,
            0x0 => Delete,
            0x7 => SingleDelete,
            0x2 => Merge,
            0xf => RangeDeletion,
            0x11 => BlobIndex,
            _ => Other,
        }
    }
}

/// <user key, sequence number, and entry type> tuple.
pub struct FullKey<'a> {
    user_key: &'a [u8],
    sequence: SequenceNumber,
    entry_type: EntryType,
}

impl ::std::fmt::Debug for FullKey<'_> {
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        f.debug_struct("FullKey")
            .field("user_key", &str::from_utf8(self.user_key))
            .field("sequence", &self.sequence)
            .field("type", &self.entry_type)
            .finish()
    }
}

impl FullKey<'_> {
    pub fn new<'b>(u: &'b [u8], seq: SequenceNumber, t: EntryType) -> FullKey<'b> {
        FullKey {
            user_key: u,
            sequence: seq,
            entry_type: t,
        }
    }

    /// Parse slice representing internal key to FullKey
    /// Parsed FullKey is valid for as long as the memory pointed to by
    /// internal_key is alive.
    pub fn parse<'b>(internal_key: &'b [u8]) -> Option<FullKey<'b>> {
        // via dbformat.h
        let n = internal_key.len();
        if n < 8 {
            return None;
        }
        let mut raw_num = [0u8; 8];
        raw_num.copy_from_slice(&internal_key[n - 8..]);
        let num: u64 = unsafe { mem::transmute(raw_num) };
        println!("num ={}", num);
        let c = (num & 0xff) as u8;
        let seq = num >> 8;
        let typ = EntryType::from_u8(c);
        let user_key = &internal_key[..n - 8];

        Some(FullKey::new(user_key, SequenceNumber(seq), typ))
    }
}
<|endoftext|>


<commit_before>use errors;
use std::result;

// see OSC Type Tag String: http://opensoundcontrol.org/spec-1_0
// padding: zero bytes (n*4)

#[derive(Debug)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    Time(u32, u32),
    // nonstandard argument types
    // ignore them if not implemented
    Long(i64),
    Double(f64),
    Char(char),
    Color(OscColor),
    Midi(OscMidiMessage),
    Bool(bool),
    Nil,
    Inf,
    Array(Vec<OscType>),
}

#[derive(Debug)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Debug)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

#[derive(Debug)]
pub struct OscMessage {
    pub addr: String,
    pub args: Option<Vec<OscType>>,
}

#[derive(Debug)]
pub struct OscBundle {
    pub timetag: OscType,
    pub content: Vec<OscPacket>,
}

#[derive(Debug)]
pub struct OscColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub alpha: u8,
}

pub type Result<T> = result::Result<T, errors::OscError>;
<commit_msg>Remove add a note<commit_after>use errors;
use std::result;

// see OSC Type Tag String: http://opensoundcontrol.org/spec-1_0
// padding: zero bytes (n*4)

#[derive(Debug)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    // use struct for time tag to avoid destructuring
    Time(u32, u32),
    Long(i64),
    Double(f64),
    Char(char),
    Color(OscColor),
    Midi(OscMidiMessage),
    Bool(bool),
    Nil,
    Inf,
    Array(Vec<OscType>),
}

#[derive(Debug)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Debug)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

#[derive(Debug)]
pub struct OscMessage {
    pub addr: String,
    pub args: Option<Vec<OscType>>,
}

#[derive(Debug)]
pub struct OscBundle {
    pub timetag: OscType,
    pub content: Vec<OscPacket>,
}

#[derive(Debug)]
pub struct OscColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub alpha: u8,
}

pub type Result<T> = result::Result<T, errors::OscError>;
<|endoftext|>


<commit_before>use app_dirs::{app_root, AppDataType, AppInfo};
use std::fs;
use std::path::{Path, PathBuf};

use errors::*;

#[cfg(not(target_os = "linux"))]
const APP_INFO: AppInfo = AppInfo {
	name: "Polaris",
	author: "Permafrost",
};

#[cfg(target_os = "linux")]
const APP_INFO: AppInfo = AppInfo {
	name: "polaris",
	author: "permafrost",
};

pub fn get_data_root() -> Result<PathBuf> {
	if let Ok(root) = app_root(AppDataType::UserData, &APP_INFO) {
		fs::create_dir_all(&root).chain_err(|| format!("opening user data: {}", root.display()))?;
		return Ok(root);
	}
	bail!("Could not retrieve data directory root");
}

#[derive(Debug, PartialEq)]
pub enum AudioFormat {
	FLAC,
	MP3,
	MP4,
	MPC,
	OGG,
}

pub fn get_audio_format(path: &Path) -> Option<AudioFormat> {
	let extension = match path.extension() {
		Some(e) => e,
		_ => return None,
	};
	let extension = match extension.to_str() {
		Some(e) => e,
		_ => return None,
	};
	match extension.to_lowercase().as_str() {
		"flac" => Some(AudioFormat::FLAC),
		"mp3" => Some(AudioFormat::MP3),
		"m4a" => Some(AudioFormat::MP4),
		"mpc" => Some(AudioFormat::MPC),
		"ogg" => Some(AudioFormat::OGG),
		_ => None,
	}
}

#[test]
fn test_get_audio_format() {
	assert_eq!(
		get_audio_format(Path::new("animals/🐷/my🐖file.jpg")),
		None
	);
	assert_eq!(
		get_audio_format(Path::new("animals/🐷/my🐖file.flac")),
		Some(AudioFormat::FLAC)
	);
}

#[test]
fn test_is_song() {
	assert!(is_song(Path::new("animals/🐷/my🐖file.mp3")));
	assert!(!is_song(Path::new("animals/🐷/my🐖file.jpg")));
}

pub fn is_image(path: &Path) -> bool {
	let extension = match path.extension() {
		Some(e) => e,
		_ => return false,
	};
	let extension = match extension.to_str() {
		Some(e) => e,
		_ => return false,
	};
	match extension.to_lowercase().as_str() {
		"png" => true,
		"gif" => true,
		"jpg" => true,
		"jpeg" => true,
		"bmp" => true,
		_ => false,
	}
}

#[test]
fn test_is_image() {
	assert!(!is_image(Path::new("animals/🐷/my🐖file.mp3")));
	assert!(is_image(Path::new("animals/🐷/my🐖file.jpg")));
}
<commit_msg>Removed outdated test<commit_after>use app_dirs::{app_root, AppDataType, AppInfo};
use std::fs;
use std::path::{Path, PathBuf};

use errors::*;

#[cfg(not(target_os = "linux"))]
const APP_INFO: AppInfo = AppInfo {
	name: "Polaris",
	author: "Permafrost",
};

#[cfg(target_os = "linux")]
const APP_INFO: AppInfo = AppInfo {
	name: "polaris",
	author: "permafrost",
};

pub fn get_data_root() -> Result<PathBuf> {
	if let Ok(root) = app_root(AppDataType::UserData, &APP_INFO) {
		fs::create_dir_all(&root).chain_err(|| format!("opening user data: {}", root.display()))?;
		return Ok(root);
	}
	bail!("Could not retrieve data directory root");
}

#[derive(Debug, PartialEq)]
pub enum AudioFormat {
	FLAC,
	MP3,
	MP4,
	MPC,
	OGG,
}

pub fn get_audio_format(path: &Path) -> Option<AudioFormat> {
	let extension = match path.extension() {
		Some(e) => e,
		_ => return None,
	};
	let extension = match extension.to_str() {
		Some(e) => e,
		_ => return None,
	};
	match extension.to_lowercase().as_str() {
		"flac" => Some(AudioFormat::FLAC),
		"mp3" => Some(AudioFormat::MP3),
		"m4a" => Some(AudioFormat::MP4),
		"mpc" => Some(AudioFormat::MPC),
		"ogg" => Some(AudioFormat::OGG),
		_ => None,
	}
}

#[test]
fn test_get_audio_format() {
	assert_eq!(
		get_audio_format(Path::new("animals/🐷/my🐖file.jpg")),
		None
	);
	assert_eq!(
		get_audio_format(Path::new("animals/🐷/my🐖file.flac")),
		Some(AudioFormat::FLAC)
	);
}

pub fn is_image(path: &Path) -> bool {
	let extension = match path.extension() {
		Some(e) => e,
		_ => return false,
	};
	let extension = match extension.to_str() {
		Some(e) => e,
		_ => return false,
	};
	match extension.to_lowercase().as_str() {
		"png" => true,
		"gif" => true,
		"jpg" => true,
		"jpeg" => true,
		"bmp" => true,
		_ => false,
	}
}

#[test]
fn test_is_image() {
	assert!(!is_image(Path::new("animals/🐷/my🐖file.mp3")));
	assert!(is_image(Path::new("animals/🐷/my🐖file.jpg")));
}
<|endoftext|>


<commit_before>/// A scale and an offset that transforms xyz coordinates.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
    /// The scale.
    pub scale: f64,
    /// The offset.
    pub offset: f64,
}

impl Transform {
    /// Applies this transform to an i32, returning a float.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(3., transform.direct(1));
    /// ```
    pub fn direct(&self, n: i32) -> f64 {
        self.scale * n as f64 + self.offset
    }

    /// Applies the inverse transform, and rounds the result.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(1, transform.inverse(2.9));
    /// ```
    pub fn inverse(&self, n: f64) -> i32 {
        ((n - self.offset) / self.scale).round() as i32
    }
}

impl Default for Transform {
    fn default() -> Transform {
        Transform {
            scale: 0.01,
            offset: 0.,
        }
    }
}
<commit_msg>Actually make it millimeter default scale<commit_after>/// A scale and an offset that transforms xyz coordinates.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
    /// The scale.
    pub scale: f64,
    /// The offset.
    pub offset: f64,
}

impl Transform {
    /// Applies this transform to an i32, returning a float.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(3., transform.direct(1));
    /// ```
    pub fn direct(&self, n: i32) -> f64 {
        self.scale * n as f64 + self.offset
    }

    /// Applies the inverse transform, and rounds the result.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(1, transform.inverse(2.9));
    /// ```
    pub fn inverse(&self, n: f64) -> i32 {
        ((n - self.offset) / self.scale).round() as i32
    }
}

impl Default for Transform {
    fn default() -> Transform {
        Transform {
            scale: 0.001,
            offset: 0.,
        }
    }
}
<|endoftext|>


<commit_before>use vec2;
use num::Num;

#[inline(always)]
pub fn compose<'a, 'b, T: Num>(out: &'a mut [T; 6], position: &'b [T; 2], scale: &'b [T; 2], rotation: T) -> &'a mut [T; 6] {
    let sx = scale[0];
    let sy = scale[1];
    let c = rotation.cos();
    let s = rotation.sin();

    out[0] = c * sx;
    out[1] = s * sx;
    out[2] = -s * sy;
    out[3] = c * sy;
    out[4] = position[0];
    out[5] = position[1];
    out
}

#[inline(always)]
pub fn decompose<'a, 'b, T: Num>(out: &'b [T; 6], position: &'a mut [T; 2], scale: &'a mut [T; 2]) -> T {
    let m11 = out[0];
    let m12 = out[1];
    let sx = vec2::length_values(m11, m12);
    let sy = vec2::length_values(out[2], out[3]);

    position[0] = out[4];
    position[1] = out[5];

    scale[0] = sx;
    scale[1] = sy;

    m12.atan2(m11)
}

#[inline(always)]
pub fn look_at<'a, 'b, T: Num>(out: &'a mut [T; 6], eye: &'b [T; 2], target: &'b [T; 2]) -> &'a mut [T; 6] {
    let x = target[0] - eye[0];
    let y = target[1] - eye[1];
    let a = y.atan2(x) - T::half_pi();
    let c = a.cos();
    let s = a.sin();

    out[0] = c;
    out[1] = s;
    out[2] = -s;
    out[3] = c;
    out
}

#[inline(always)]
pub fn set_rotation<'a, 'b, T: Num>(out: &'a mut [T; 6], rotation: T) -> &'a mut [T; 6] {
    let c = rotation.cos();
    let s = rotation.sin();

    out[0] = c;
    out[1] = s;
    out[2] = -s;
    out[3] = c;
    out
}
#[test]
fn test_set_rotation() {
    use core::f32;
    use create;
    use misc;

    let mut m = create::new_identity::<f32>();
    set_rotation(&mut m, f32::consts::FRAC_PI_2);

    assert!(misc::eq(&m, &[0f32, 1f32, -1f32, 0f32, 0f32, 0f32]));
}

#[inline(always)]
pub fn get_rotation<'a, 'b, T: Num>(out: &'b [T; 6]) -> T {
    out[1].atan2(out[0])
}
#[test]
fn test_get_rotation() {
    use core::f32;
    use create;

    let mut m = create::new_identity::<f32>();
    set_rotation(&mut m, f32::consts::FRAC_PI_2);

    assert_eq!(get_rotation(&m), f32::consts::FRAC_PI_2);
}

#[inline(always)]
pub fn set_position<'a, 'b, T: Num>(out: &'a mut [T; 6], v: &'b [T; 2]) -> &'a mut [T; 6] {
    out[4] = v[0];
    out[5] = v[1];
    out
}

#[inline(always)]
pub fn get_position<'a, 'b, T: Num>(out: &'b [T; 6], v: &'a mut [T; 2]) -> &'a mut [T; 2] {
    v[0] = out[4];
    v[1] = out[5];
    v
}

#[inline(always)]
pub fn extract_position<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6]) -> &'a mut [T; 6] {
    out[4] = a[4];
    out[5] = a[5];
    out
}

#[inline(always)]
pub fn extract_rotation<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6]) -> &'a mut [T; 6] {
    let m11 = a[0];
    let m12 = a[2];
    let m21 = a[1];
    let m22 = a[3];

    let x = m11 * m11 + m21 * m21;
    let y = m12 * m12 + m22 * m22;

    let sx = if x != T::zero() {T::one() / x.sqrt()} else {T::zero()};
    let sy = if y != T::zero() {T::one() / y.sqrt()} else {T::zero()};

    out[0] = m11 * sx;
    out[1] = m21 * sx;
    out[2] = m12 * sy;
    out[3] = m22 * sy;
    out
}

#[inline(always)]
pub fn translate<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6], v: &'b [T; 2]) -> &'a mut [T; 6] {
    out[4] = a[0] * v[0] + a[2] * v[1] + a[4];
    out[5] = a[1] * v[0] + a[3] * v[1] + a[5];
    out
}

#[inline(always)]
pub fn rotate<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6], rotation: T) -> &'a mut [T; 6] {
    let m11 = a[0];
    let m12 = a[2];
    let m21 = a[1];
    let m22 = a[3];
    let c = rotation.cos();
    let s = rotation.sin();

    out[0] = m11 * c + m12 * -s;
    out[1] = m11 * s + m12 * c;
    out[2] = m21 * c + m22 * -s;
    out[3] = m21 * s + m22 * c;
    out
}
#[test]
fn test_rotate() {
    use core::f32;
    use create;
    use misc;

    let mut m = create::new_identity::<f32>();
    rotate(&mut m, &create::new_identity::<f32>(), f32::consts::FRAC_PI_2);

    assert!(misc::eq(&m, &[
        0f32, 1f32, -1f32, 0f32, 0f32, 0f32
    ]));
}

#[inline(always)]
pub fn scale<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6], v: &'b [T; 2]) -> &'a mut [T; 6] {
    let x = v[0];
    let y = v[1];

    out[0] = a[0] * x;
    out[1] = a[1] * x;

    out[2] = a[2] * y;
    out[3] = a[3] * y;

    out
}

#[inline(always)]
pub fn orthographic<'a, 'b, T: Num>(out: &'a mut [T; 6], left: T, right: T, top: T, bottom: T) -> &'a mut [T; 6] {
    let w = right - left;
    let h = top - bottom;

    let x = (right + left) / w;
    let y = (top + bottom) / h;

    out[0] = T::from_isize(2isize) / w;
    out[1] = T::zero();
    out[2] = T::zero();
    out[3] = T::from_isize(2isize) / h;
    out[4] = -x;
    out[5] = -y;

    out
}
<commit_msg>clean up<commit_after>use vec2;
use num::Num;

#[inline(always)]
pub fn compose<'a, 'b, T: Num>(out: &'a mut [T; 6], position: &'b [T; 2], scale: &'b [T; 2], rotation: T) -> &'a mut [T; 6] {
    let sx = scale[0];
    let sy = scale[1];
    let c = rotation.cos();
    let s = rotation.sin();

    out[0] = c * sx;
    out[1] = s * sx;
    out[2] = -s * sy;
    out[3] = c * sy;
    out[4] = position[0];
    out[5] = position[1];
    out
}

#[inline(always)]
pub fn decompose<'a, 'b, T: Num>(out: &'b [T; 6], position: &'a mut [T; 2], scale: &'a mut [T; 2]) -> T {
    let m11 = out[0];
    let m12 = out[1];
    let sx = vec2::length_values(m11, m12);
    let sy = vec2::length_values(out[2], out[3]);

    position[0] = out[4];
    position[1] = out[5];

    scale[0] = sx;
    scale[1] = sy;

    m12.atan2(m11)
}

#[inline(always)]
pub fn look_at<'a, 'b, T: Num>(out: &'a mut [T; 6], eye: &'b [T; 2], target: &'b [T; 2]) -> &'a mut [T; 6] {
    let x = target[0] - eye[0];
    let y = target[1] - eye[1];
    let a = y.atan2(x) - T::half_pi();
    let c = a.cos();
    let s = a.sin();

    out[0] = c;
    out[1] = s;
    out[2] = -s;
    out[3] = c;
    out
}

#[inline(always)]
pub fn set_rotation<'a, 'b, T: Num>(out: &'a mut [T; 6], rotation: T) -> &'a mut [T; 6] {
    let c = rotation.cos();
    let s = rotation.sin();

    out[0] = c;
    out[1] = s;
    out[2] = -s;
    out[3] = c;
    out
}
#[test]
fn test_set_rotation() {
    use core::f32;
    use create;
    use misc;

    let mut m = create::new_identity::<f32>();
    set_rotation(&mut m, f32::consts::FRAC_PI_2);

    assert!(misc::eq(&m, &[0f32, 1f32, -1f32, 0f32, 0f32, 0f32]));
}

#[inline(always)]
pub fn get_rotation<'a, 'b, T: Num>(out: &'b [T; 6]) -> T {
    out[1].atan2(out[0])
}
#[test]
fn test_get_rotation() {
    use core::f32;
    use create;

    let mut m = create::new_identity::<f32>();
    set_rotation(&mut m, f32::consts::FRAC_PI_2);

    assert_eq!(get_rotation(&m), f32::consts::FRAC_PI_2);
}

#[inline(always)]
pub fn set_position<'a, 'b, T: Num>(out: &'a mut [T; 6], v: &'b [T; 2]) -> &'a mut [T; 6] {
    out[4] = v[0];
    out[5] = v[1];
    out
}

#[inline(always)]
pub fn get_position<'a, 'b, T: Num>(out: &'b [T; 6], v: &'a mut [T; 2]) -> &'a mut [T; 2] {
    v[0] = out[4];
    v[1] = out[5];
    v
}

#[inline(always)]
pub fn extract_position<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6]) -> &'a mut [T; 6] {
    out[4] = a[4];
    out[5] = a[5];
    out
}

#[inline(always)]
pub fn extract_rotation<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6]) -> &'a mut [T; 6] {
    let m11 = a[0];
    let m12 = a[2];
    let m21 = a[1];
    let m22 = a[3];

    let x = m11 * m11 + m21 * m21;
    let y = m12 * m12 + m22 * m22;

    let sx = if x != T::zero() {T::one() / x.sqrt()} else {T::zero()};
    let sy = if y != T::zero() {T::one() / y.sqrt()} else {T::zero()};

    out[0] = m11 * sx;
    out[1] = m21 * sx;
    out[2] = m12 * sy;
    out[3] = m22 * sy;
    out
}

#[inline(always)]
pub fn translate<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6], v: &'b [T; 2]) -> &'a mut [T; 6] {
    out[4] = a[0] * v[0] + a[2] * v[1] + a[4];
    out[5] = a[1] * v[0] + a[3] * v[1] + a[5];
    out
}

#[inline(always)]
pub fn rotate<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6], rotation: T) -> &'a mut [T; 6] {
    let m11 = a[0];
    let m12 = a[2];
    let m21 = a[1];
    let m22 = a[3];
    let c = rotation.cos();
    let s = rotation.sin();

    out[0] = m11 * c + m12 * -s;
    out[1] = m11 * s + m12 * c;
    out[2] = m21 * c + m22 * -s;
    out[3] = m21 * s + m22 * c;
    out
}
#[test]
fn test_rotate() {
    use core::f32;
    use create;
    use misc;

    let mut m = create::new_identity::<f32>();
    rotate(&mut m, &create::new_identity::<f32>(), f32::consts::FRAC_PI_2);

    assert!(misc::eq(&m, &[
        0f32, 1f32, -1f32, 0f32, 0f32, 0f32
    ]));
}

#[inline(always)]
pub fn scale<'a, 'b, T: Num>(out: &'a mut [T; 6], a: &'b [T; 6], v: &'b [T; 2]) -> &'a mut [T; 6] {
    let x = v[0];
    let y = v[1];

    out[0] = a[0] * x;
    out[1] = a[1] * x;

    out[2] = a[2] * y;
    out[3] = a[3] * y;

    out
}

#[inline(always)]
pub fn orthographic<'a, 'b, T: Num>(out: &'a mut [T; 6], top: T, right: T, bottom: T, left: T) -> &'a mut [T; 6] {
    let w = right - left;
    let h = top - bottom;

    let x = (right + left) / w;
    let y = (top + bottom) / h;

    out[0] = T::from_isize(2isize) / w;
    out[1] = T::zero();
    out[2] = T::zero();
    out[3] = T::from_isize(2isize) / h;
    out[4] = -x;
    out[5] = -y;

    out
}
<|endoftext|>


<commit_before>use native::task;
use std::comm::channel;

pub struct WorkUnit<ARG, RV> {
    arg: ARG,
    rv: Sender<RV>,
}

pub enum MessageToWorker<ARG, RV> {
    Work(WorkUnit<ARG, RV>),
    Halt,
}

pub enum MessageToDispatcher<ARG, RV> {
    Dispatch(WorkUnit<ARG, RV>),
    HaltAll,
    RegisterWorker(Sender<Sender<Sender<MessageToWorker<ARG, RV>>>>),
}

pub struct WorkQueue<ARG, RV> {
    dispatcher: Sender<MessageToDispatcher<ARG, RV>>,
}

pub struct WorkQueueProxy<ARG, RV> {
    dispatcher: Sender<MessageToDispatcher<ARG, RV>>,
}

impl<ARG:Send, RV:Send> WorkQueue<ARG, RV> {
    pub fn create() -> WorkQueue<ARG, RV> {
        let (dispatcher, dispatcher_inbox) = channel::<MessageToDispatcher<ARG, RV>>();

        // dispatcher
        task::spawn(proc() {
            let (want_work, idle_worker) = channel::<Sender<MessageToWorker<ARG, RV>>>();
            let mut worker_count = 0;
            let inbox = dispatcher_inbox;
            let idle_worker = idle_worker;
            loop {
                match inbox.recv() {
                    Dispatch(work_item) => {
                        idle_worker.recv().send(Work(work_item));
                    },
                    RegisterWorker(want_idle_sender) => {
                        worker_count += 1;
                        want_idle_sender.send(want_work.clone());
                    }
                    HaltAll => {
                        while worker_count > 0 {
                            idle_worker.recv().send(Halt);
                            worker_count -= 1;
                        }
                        return;
                    },
                };
            }
        });
        return WorkQueue{dispatcher: dispatcher};
    }

    pub fn proxy(&self) -> WorkQueueProxy<ARG, RV> {
        return WorkQueueProxy{dispatcher: self.dispatcher.clone()};
    }

    pub fn register_worker(&self) -> Sender<Sender<MessageToWorker<ARG, RV>>> {
        let (reg_s, reg_r) = channel::<Sender<Sender<MessageToWorker<ARG, RV>>>>();
        self.dispatcher.send(RegisterWorker(reg_s));
        return reg_r.recv();
    }

    pub fn push(&self, arg: ARG) -> Receiver<RV> {
        let (rv, wait_for_rv) = channel::<RV>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, rv: rv}));
        return wait_for_rv;
    }
}

// rustc complais "cannot implement a destructor on a structure with
// type parameters", but our destruction is safe, we only send
// a simple message on a channel.
#[unsafe_destructor]
impl<ARG:Send, RV:Send> Drop for WorkQueue<ARG, RV> {
    fn drop(&mut self) {
        self.dispatcher.send(HaltAll);
    }
}

impl<ARG:Send, RV:Send> WorkQueueProxy<ARG, RV> {
    pub fn push(&self, arg: ARG) -> Receiver<RV> {
        let (rv, wait_for_rv) = channel::<RV>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, rv: rv}));
        return wait_for_rv;
    }
}

impl<ARG:Send, RV:Send> Clone for WorkQueueProxy<ARG, RV> {
    fn clone(&self) -> WorkQueueProxy<ARG, RV> {
        return WorkQueueProxy{dispatcher: self.dispatcher.clone()};
    }
}

#[cfg(test)]
fn spawn_test_worker(queue: &WorkQueue<int, int>) {
    let want_work = queue.register_worker();
    task::spawn(proc() {
        let want_work = want_work;
        loop {
            let (idle, get_work_unit) = channel::<MessageToWorker<int, int>>();
            want_work.send(idle);
            let work_unit = match get_work_unit.recv() {
                Work(wu) => wu,
                Halt     => return
            };
            let rv = work_unit.arg * 2;
            work_unit.rv.send(rv);
        }
    });
}

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

    use native::task;
    use super::{WorkQueue, spawn_test_worker};

    #[test]
    fn test_queue() {
        let queue = WorkQueue::<int, int>::create();
        for _ in range(0, 3) {
            spawn_test_worker(&queue);
        }

        let return_list: ~[int] =
            range(0, 10)
            .map(|c| queue.push(c))
            .map(|rv| rv.recv())
            .collect();

        assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
    }

    #[test]
    fn test_enqueue_from_tasks() {
        let queue = WorkQueue::<int, int>::create();
        for _ in range(0, 3) {
            spawn_test_worker(&queue);
        }
        let mut promise_list: ~[Receiver<int>] = ~[];
        let queue_proxy = queue.proxy();
        for c in range(0, 10) {
            let queue_proxy_clone = queue_proxy.clone();
            let (done, promise) = channel::<int>();
            promise_list.push(promise);
            task::spawn(proc() {
                let done = done;
                let queue = queue_proxy_clone;
                let rv = queue.push(c);
                done.send(rv.recv());
            });
        }

        let return_list: ~[int] =
            promise_list
            .iter()
            .map(|promise| promise.recv())
            .collect();
        assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
    }
}

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

    use self::test::BenchHarness;
    use super::{WorkQueue, spawn_test_worker};

    #[bench]
    fn bench_50_tasks_4_threads(b: &mut BenchHarness) {
        let queue = WorkQueue::<int, int>::create();
        for _ in range(0, 4) {
            spawn_test_worker(&queue);
        }
        b.iter(|| {
            let _: ~[int] =
                range(0, 50)
                .map(|_| queue.push(1))
                .map(|rv| rv.recv())
                .collect();
        });
    }

    #[bench]
    fn bench_spawn_5_workers(b: &mut BenchHarness) {
        b.iter(|| {
            let queue = WorkQueue::<int, int>::create();
            for _ in range(0, 5) {
                spawn_test_worker(&queue);
            }
        });
    }
}
<commit_msg>skeleton docs<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! write docs here

use native::task;
use std::comm::channel;

/// write docs here
pub struct WorkUnit<ARG, RV> {
    /// Argument that will be passed to the worker.
    arg: ARG,
    /// Sender end of a channel. Worker will send its return value here.
    rv: Sender<RV>,
}

/// write docs here
pub enum MessageToWorker<ARG, RV> {
    /// A work unit.
    Work(WorkUnit<ARG, RV>),
    /// Shut down the worker task.
    Halt,
}

/// write docs here
pub enum MessageToDispatcher<ARG, RV> {
    /// A work unit that needs to be dispatched to a worker task.
    Dispatch(WorkUnit<ARG, RV>),
    /// Halt all worker tasks.
    HaltAll,
    /// Register a new worker task.
    RegisterWorker(Sender<Sender<Sender<MessageToWorker<ARG, RV>>>>),
}

/// A queue that distributes work items to worker tasks.
pub struct WorkQueue<ARG, RV> {
    /// write docs here
    dispatcher: Sender<MessageToDispatcher<ARG, RV>>,
}

/// A proxy to a `WorkQueue`. It can be freely cloned to use from multiple tasks.
pub struct WorkQueueProxy<ARG, RV> {
    /// write docs here
    dispatcher: Sender<MessageToDispatcher<ARG, RV>>,
}

impl<ARG:Send, RV:Send> WorkQueue<ARG, RV> {
    /// Create a new work queue.
    pub fn create() -> WorkQueue<ARG, RV> {
        let (dispatcher, dispatcher_inbox) = channel::<MessageToDispatcher<ARG, RV>>();
        task::spawn(proc() {
            let (want_work, idle_worker) = channel::<Sender<MessageToWorker<ARG, RV>>>();
            let mut worker_count = 0;
            let inbox = dispatcher_inbox;
            let idle_worker = idle_worker;
            loop {
                match inbox.recv() {
                    Dispatch(work_item) => {
                        idle_worker.recv().send(Work(work_item));
                    },
                    RegisterWorker(want_idle_sender) => {
                        worker_count += 1;
                        want_idle_sender.send(want_work.clone());
                    }
                    HaltAll => {
                        while worker_count > 0 {
                            idle_worker.recv().send(Halt);
                            worker_count -= 1;
                        }
                        return;
                    },
                };
            }
        });
        return WorkQueue{dispatcher: dispatcher};
    }

    /// Create a copyable proxy that can be used to push work units.
    pub fn proxy(&self) -> WorkQueueProxy<ARG, RV> {
        return WorkQueueProxy{dispatcher: self.dispatcher.clone()};
    }

    /// Register a new worker. It will receive a sender where it can ask for tasks.
    pub fn register_worker(&self) -> Sender<Sender<MessageToWorker<ARG, RV>>> {
        let (reg_s, reg_r) = channel::<Sender<Sender<MessageToWorker<ARG, RV>>>>();
        self.dispatcher.send(RegisterWorker(reg_s));
        return reg_r.recv();
    }

    /// Push a work item to this queue.
    pub fn push(&self, arg: ARG) -> Receiver<RV> {
        let (rv, wait_for_rv) = channel::<RV>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, rv: rv}));
        return wait_for_rv;
    }
}

// rustc complais "cannot implement a destructor on a structure with
// type parameters", but our destruction is safe, we only send
// a simple message on a channel.
#[unsafe_destructor]
impl<ARG:Send, RV:Send> Drop for WorkQueue<ARG, RV> {
    fn drop(&mut self) {
        self.dispatcher.send(HaltAll);
    }
}

impl<ARG:Send, RV:Send> WorkQueueProxy<ARG, RV> {
    /// Push a work item to this queue.
    pub fn push(&self, arg: ARG) -> Receiver<RV> {
        let (rv, wait_for_rv) = channel::<RV>();
        self.dispatcher.send(Dispatch(WorkUnit{arg: arg, rv: rv}));
        return wait_for_rv;
    }
}

impl<ARG:Send, RV:Send> Clone for WorkQueueProxy<ARG, RV> {
    fn clone(&self) -> WorkQueueProxy<ARG, RV> {
        return WorkQueueProxy{dispatcher: self.dispatcher.clone()};
    }
}

#[cfg(test)]
fn spawn_test_worker(queue: &WorkQueue<int, int>) {
    let want_work = queue.register_worker();
    task::spawn(proc() {
        let want_work = want_work;
        loop {
            let (idle, get_work_unit) = channel::<MessageToWorker<int, int>>();
            want_work.send(idle);
            let work_unit = match get_work_unit.recv() {
                Work(wu) => wu,
                Halt     => return
            };
            let rv = work_unit.arg * 2;
            work_unit.rv.send(rv);
        }
    });
}

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

    use native::task;
    use super::{WorkQueue, spawn_test_worker};

    #[test]
    fn test_queue() {
        let queue = WorkQueue::<int, int>::create();
        for _ in range(0, 3) {
            spawn_test_worker(&queue);
        }

        let return_list: ~[int] =
            range(0, 10)
            .map(|c| queue.push(c))
            .map(|rv| rv.recv())
            .collect();

        assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
    }

    #[test]
    fn test_enqueue_from_tasks() {
        let queue = WorkQueue::<int, int>::create();
        for _ in range(0, 3) {
            spawn_test_worker(&queue);
        }
        let mut promise_list: ~[Receiver<int>] = ~[];
        let queue_proxy = queue.proxy();
        for c in range(0, 10) {
            let queue_proxy_clone = queue_proxy.clone();
            let (done, promise) = channel::<int>();
            promise_list.push(promise);
            task::spawn(proc() {
                let done = done;
                let queue = queue_proxy_clone;
                let rv = queue.push(c);
                done.send(rv.recv());
            });
        }

        let return_list: ~[int] =
            promise_list
            .iter()
            .map(|promise| promise.recv())
            .collect();
        assert_eq!(return_list, ~[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
    }
}

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

    use self::test::BenchHarness;
    use super::{WorkQueue, spawn_test_worker};

    #[bench]
    fn bench_50_tasks_4_threads(b: &mut BenchHarness) {
        let queue = WorkQueue::<int, int>::create();
        for _ in range(0, 4) {
            spawn_test_worker(&queue);
        }
        b.iter(|| {
            let _: ~[int] =
                range(0, 50)
                .map(|_| queue.push(1))
                .map(|rv| rv.recv())
                .collect();
        });
    }

    #[bench]
    fn bench_spawn_5_workers(b: &mut BenchHarness) {
        b.iter(|| {
            let queue = WorkQueue::<int, int>::create();
            for _ in range(0, 5) {
                spawn_test_worker(&queue);
            }
        });
    }
}
<|endoftext|>


<commit_before>//! Adaptors for object-safe hashing.
//!
//! `std::hash::Hash` is not object-safe because trait function `hash` takes
//! a type parameter that specifies the concrete hash implementation used.
//!
//! This module defines a trait [`Hashable`](trait.Hashable.html), which can be
//! implemented identically to `std::hash::Hash` but accepts the hash-state
//! object as a trait object (`state: &Hasher`) and thus requires no type
//! parameters on function `hash`.
//!
//! For this reason, `Hashable` is entirely agnostic to the hash implementation
//! being used; any trait object that specifies `Hashable` as a supertrait, and
//! implements `Hash` in terms of Hashable, may be safely used as a (boxed)
//! type parameter to containers like `HashSet`.
//!
//! TL;DR => if you want to hash instances of a type using dynamic dispatch
//! through a trait it implements, you must:
//!
//!
//!   1. ensure that the trait lists `Hashable` as a supertrait, and implements
//!      `std::hash::Hash` in terms of `Hashable`;
//!
//!      ```rust,ignore
//!      trait MyTrait: Hashable {
//!          // ...
//!      }
//!
//!      impl std::hash::Hash for MyTrait {
//!          fn hash<H: Hasher>(&self, state: &mut H) {
//!              <Self as Hashable>::hash(self, state);
//!          }
//!      }
//!      ```
//!
//!      and
//!
//!   2. implement `Hashable` for each concrete type that implements the trait.
//!
//!      ```rust,ignore
//!      impl Hashable for MyType {
//!          fn hash(&self, state: &mut std::hash::Hasher) {
//!              // function body should be identical to that of
//!              // an implementation of `Hash::hash`.
//!          }
//!      }
//!      ```
//!
//!
//! ## Complete Example
//!
//! ```rust
//! #![feature(hash)]
//! use std::cmp::{Eq,PartialEq};
//! use std::hash::{Hash,Hasher,SipHasher};
//! use std::collections::HashSet;
//!
//! use cripes::util::hash::{stdhash,hash,Hashable};
//!
//! trait MyInterface: Hashable {}
//!
//! impl Eq for MyInterface {}
//! impl PartialEq<MyInterface> for MyInterface {
//!     fn eq(&self, other: &MyInterface) -> bool {
//!         hash::<_,SipHasher>(self) == hash::<_,SipHasher>(other)
//!     }
//! }
//!
//! impl std::hash::Hash for MyInterface {
//!     fn hash<H: Hasher>(&self, state: &mut H) {
//!         <Self as Hashable>::hash(self, state)
//!     }
//! }
//!
//!
//! #[derive(Eq,PartialEq)]
//! struct MyType(u64, &'static str);
//!
//! impl MyInterface for MyType {}
//! impl Hashable for MyType {
//!     fn hash(&self, state: &mut Hasher) {
//!         state.write_u64(self.0);
//!         state.write(self.1.as_bytes());
//!     }
//! }
//!
//! fn main() {
//!     use std::collections::HashSet;
//!
//!     let mut hs: HashSet<Box<MyInterface>> = HashSet::new();
//!     hs.insert(Box::new(MyType(123, "abc")));
//!
//!     // ...
//!
//!     for x in &hs {
//!         println!("{}", stdhash::<_,SipHasher>(x));
//!     }
//! }
//!
//! ```
//!
use std::default::Default;
use std::hash::{Hash,Hasher};

/// Object-safe hash adaptor.  See the [module-level documentation](index.html)
/// for details.
pub trait Hashable {
    /// Feed `self` to a Hasher object.
    fn hash(&self, state: &mut Hasher);
}

/// Hash `char` as a `u32`.
impl Hashable for char {
    #[inline(always)]
    fn hash(&self, state: &mut Hasher) {
        state.write_u32(*self as u32);
    }
}

/// Produce a one-time hash of a value using the standard Hasher interface.
pub fn stdhash<T: Hash,H: Default + Hasher>(t: &T) -> u64 {
    let mut s = H::default();
    t.hash(&mut s);
    s.finish()
}

/// Hash an object by using the Hashable interface directly.
///
///
pub fn hash<T: ?Sized, H>(obj: &T) -> u64 where H: Hasher + Default, T: Hashable {
    let mut state: H = Default::default();
    obj.hash(&mut state);
    state.finish()
}
<commit_msg>util/hash: update doc-example `use` and feature declarations<commit_after>//! Adaptors for object-safe hashing.
//!
//! `std::hash::Hash` is not object-safe because trait function `hash` takes
//! a type parameter that specifies the concrete hash implementation used.
//!
//! This module defines a trait [`Hashable`](trait.Hashable.html), which can be
//! implemented identically to `std::hash::Hash` but accepts the hash-state
//! object as a trait object (`state: &Hasher`) and thus requires no type
//! parameters on function `hash`.
//!
//! For this reason, `Hashable` is entirely agnostic to the hash implementation
//! being used; any trait object that specifies `Hashable` as a supertrait, and
//! implements `Hash` in terms of Hashable, may be safely used as a (boxed)
//! type parameter to containers like `HashSet`.
//!
//! TL;DR => if you want to hash instances of a type using dynamic dispatch
//! through a trait it implements, you must:
//!
//!
//!   1. ensure that the trait lists `Hashable` as a supertrait, and implements
//!      `std::hash::Hash` in terms of `Hashable`;
//!
//!      ```rust,ignore
//!      trait MyTrait: Hashable {
//!          // ...
//!      }
//!
//!      impl std::hash::Hash for MyTrait {
//!          fn hash<H: Hasher>(&self, state: &mut H) {
//!              <Self as Hashable>::hash(self, state);
//!          }
//!      }
//!      ```
//!
//!      and
//!
//!   2. implement `Hashable` for each concrete type that implements the trait.
//!
//!      ```rust,ignore
//!      impl Hashable for MyType {
//!          fn hash(&self, state: &mut std::hash::Hasher) {
//!              // function body should be identical to that of
//!              // an implementation of `Hash::hash`.
//!          }
//!      }
//!      ```
//!
//!
//! ## Complete Example
//!
//! ```rust
//! use std::cmp::{Eq,PartialEq};
//! use std::hash::{Hasher, SipHasher};
//!
//! use cripes::util::hash::{stdhash,hash,Hashable};
//!
//! trait MyInterface: Hashable {}
//!
//! impl Eq for MyInterface {}
//! impl PartialEq<MyInterface> for MyInterface {
//!     fn eq(&self, other: &MyInterface) -> bool {
//!         hash::<_,SipHasher>(self) == hash::<_,SipHasher>(other)
//!     }
//! }
//!
//! impl std::hash::Hash for MyInterface {
//!     fn hash<H: Hasher>(&self, state: &mut H) {
//!         <Self as Hashable>::hash(self, state)
//!     }
//! }
//!
//!
//! #[derive(Eq,PartialEq)]
//! struct MyType(u64, &'static str);
//!
//! impl MyInterface for MyType {}
//! impl Hashable for MyType {
//!     fn hash(&self, state: &mut Hasher) {
//!         state.write_u64(self.0);
//!         state.write(self.1.as_bytes());
//!     }
//! }
//!
//! fn main() {
//!     use std::collections::HashSet;
//!
//!     let mut hs: HashSet<Box<MyInterface>> = HashSet::new();
//!     hs.insert(Box::new(MyType(123, "abc")));
//!
//!     // ...
//!
//!     for x in &hs {
//!         println!("{}", stdhash::<_,SipHasher>(x));
//!     }
//! }
//!
//! ```
//!
use std::default::Default;
use std::hash::{Hash,Hasher};

/// Object-safe hash adaptor.  See the [module-level documentation](index.html)
/// for details.
pub trait Hashable {
    /// Feed `self` to a Hasher object.
    fn hash(&self, state: &mut Hasher);
}

/// Hash `char` as a `u32`.
impl Hashable for char {
    #[inline(always)]
    fn hash(&self, state: &mut Hasher) {
        state.write_u32(*self as u32);
    }
}

/// Produce a one-time hash of a value using the standard Hasher interface.
pub fn stdhash<T: Hash,H: Default + Hasher>(t: &T) -> u64 {
    let mut s = H::default();
    t.hash(&mut s);
    s.finish()
}

/// Hash an object by using the Hashable interface directly.
///
///
pub fn hash<T: ?Sized, H>(obj: &T) -> u64 where H: Hasher + Default, T: Hashable {
    let mut state: H = Default::default();
    obj.hash(&mut state);
    state.finish()
}
<|endoftext|>