<commit_before>use futures::sync::oneshot;
use futures::{future, Future};
use futures;
use std;
use std::borrow::Cow;
use std::io::{Read, Seek, SeekFrom, Result};
use std::mem;
use std::sync::mpsc::{RecvError, TryRecvError, RecvTimeoutError};
use std::thread;
use std::time::Duration;

use config::{Bitrate, PlayerConfig};
use core::session::Session;
use core::spotify_id::SpotifyId;

use audio_backend::Sink;
use audio::{AudioFile, AudioDecrypt};
use audio::{VorbisDecoder, VorbisPacket};
use metadata::{FileFormat, Track, Metadata};
use mixer::AudioFilter;

pub struct Player {
    commands: Option<std::sync::mpsc::Sender<PlayerCommand>>,
    thread_handle: Option<thread::JoinHandle<()>>,
}

struct PlayerInternal {
    session: Session,
    config: PlayerConfig,
    commands: std::sync::mpsc::Receiver<PlayerCommand>,

    state: PlayerState,
    sink: Box<Sink>,
    sink_running: bool,
    audio_filter: Option<Box<AudioFilter + Send>>,
    event_sender: futures::sync::mpsc::UnboundedSender<PlayerEvent>,
}

enum PlayerCommand {
    Load(SpotifyId, bool, u32, oneshot::Sender<()>),
    Play,
    Pause,
    Stop,
    Seek(u32),
}

#[derive(Debug, Clone)]
pub enum PlayerEvent {
    Started {
        track_id: SpotifyId,
    },

    Changed {
        old_track_id: SpotifyId,
        new_track_id: SpotifyId,
    },

    Stopped {
        track_id: SpotifyId,
    }
}

type PlayerEventChannel = futures::sync::mpsc::UnboundedReceiver<PlayerEvent>;
impl Player {
    pub fn new<F>(config: PlayerConfig, session: Session,
                  audio_filter: Option<Box<AudioFilter + Send>>,
                  sink_builder: F) -> (Player, PlayerEventChannel)
        where F: FnOnce() -> Box<Sink> + Send + 'static
    {
        let (cmd_tx, cmd_rx) = std::sync::mpsc::channel();
        let (event_sender, event_receiver) = futures::sync::mpsc::unbounded();

        let handle = thread::spawn(move || {
            debug!("new Player[{}]", session.session_id());

            let internal = PlayerInternal {
                session: session,
                config: config,
                commands: cmd_rx,

                state: PlayerState::Stopped,
                sink: sink_builder(),
                sink_running: false,
                audio_filter: audio_filter,
                event_sender: event_sender,
            };

            internal.run();
        });

        (Player { commands: Some(cmd_tx), thread_handle: Some(handle) },
         event_receiver)
    }

    fn command(&self, cmd: PlayerCommand) {
        self.commands.as_ref().unwrap().send(cmd).unwrap();
    }

    pub fn load(&self, track: SpotifyId, start_playing: bool, position_ms: u32)
        -> oneshot::Receiver<()>
    {
        let (tx, rx) = oneshot::channel();
        self.command(PlayerCommand::Load(track, start_playing, position_ms, tx));

        rx
    }

    pub fn play(&self) {
        self.command(PlayerCommand::Play)
    }

    pub fn pause(&self) {
        self.command(PlayerCommand::Pause)
    }

    pub fn stop(&self) {
        self.command(PlayerCommand::Stop)
    }

    pub fn seek(&self, position_ms: u32) {
        self.command(PlayerCommand::Seek(position_ms));
    }
}

impl Drop for Player {
    fn drop(&mut self) {
        debug!("Shutting down player thread ...");
        self.commands = None;
        if let Some(handle) = self.thread_handle.take() {
            match handle.join() {
                Ok(_) => (),
                Err(_) => error!("Player thread panicked!")
            }
        }
    }
}

type Decoder = VorbisDecoder<Subfile<AudioDecrypt<AudioFile>>>;
enum PlayerState {
    Stopped,
    Paused {
        track_id: SpotifyId,
        decoder: Decoder,
        end_of_track: oneshot::Sender<()>,
    },
    Playing {
        track_id: SpotifyId,
        decoder: Decoder,
        end_of_track: oneshot::Sender<()>,
    },
    EndOfTrack { track_id: SpotifyId },
    Invalid,
}

impl PlayerState {
    fn is_playing(&self) -> bool {
        use self::PlayerState::*;
        match *self {
            Stopped | EndOfTrack { .. } | Paused { .. } => false,
            Playing { .. } => true,
            Invalid => panic!("invalid state"),
        }
    }

    fn decoder(&mut self) -> Option<&mut Decoder> {
        use self::PlayerState::*;
        match *self {
            Stopped | EndOfTrack { .. } => None,
            Paused { ref mut decoder, .. } |
            Playing { ref mut decoder, .. } => Some(decoder),
            Invalid => panic!("invalid state"),
        }
    }

    fn playing_to_end_of_track(&mut self) {
        use self::PlayerState::*;
        match mem::replace(self, Invalid) {
            Playing { track_id, end_of_track, ..} => {
                end_of_track.send(());
                let old_state = mem::replace(self, EndOfTrack { track_id });
            },
            _ => panic!("Called playing_to_end_of_track in non-playing state.")
        }
    }

    fn paused_to_playing(&mut self) {
        use self::PlayerState::*;
        match ::std::mem::replace(self, Invalid) {
            Paused { decoder, end_of_track, track_id } => {
                *self = Playing {
                    decoder: decoder,
                    end_of_track: end_of_track,
                    track_id: track_id,
                };
            }
            _ => panic!("invalid state"),
        }
    }

    fn playing_to_paused(&mut self) {
        use self::PlayerState::*;
        match ::std::mem::replace(self, Invalid) {
            Playing { decoder, end_of_track, track_id } => {
                *self = Paused {
                    decoder: decoder,
                    end_of_track: end_of_track,
                    track_id: track_id,
                };
            }
            _ => panic!("invalid state"),
        }
    }
}

impl PlayerInternal {
    fn run(mut self) {
        loop {
            let cmd = if self.state.is_playing() {
                if self.sink_running
                {
                    match self.commands.try_recv() {
                        Ok(cmd) => Some(cmd),
                        Err(TryRecvError::Empty) => None,
                        Err(TryRecvError::Disconnected) => return,
                    }
                }
                else
                {
                    match self.commands.recv_timeout(Duration::from_secs(5)) {
                        Ok(cmd) => Some(cmd),
                        Err(RecvTimeoutError::Timeout) => None,
                        Err(RecvTimeoutError::Disconnected) => return,
                    }
                }
            } else {
                match self.commands.recv() {
                    Ok(cmd) => Some(cmd),
                    Err(RecvError) => return,
                }
            };

            if let Some(cmd) = cmd {
                self.handle_command(cmd);
            }

            if self.state.is_playing() && ! self.sink_running {
                self.start_sink();
            }

            if self.sink_running {
                let packet = if let PlayerState::Playing { ref mut decoder, .. } = self.state {
                    Some(decoder.next_packet().expect("Vorbis error"))
                } else {
                    None
                };

                if let Some(packet) = packet {
                    self.handle_packet(packet);
                }
            }
        }
    }

    fn start_sink(&mut self) {
        match self.sink.start() {
            Ok(()) => self.sink_running = true,
            Err(err) => error!("Could not start audio: {}", err),
        }
    }

    fn stop_sink_if_running(&mut self) {
        if self.sink_running {
            self.stop_sink();
        }
    }

    fn stop_sink(&mut self) {
        self.sink.stop().unwrap();
        self.sink_running = false;
    }

    fn handle_packet(&mut self, packet: Option<VorbisPacket>) {
        match packet {
            Some(mut packet) => {
                if let Some(ref editor) = self.audio_filter {
                    editor.modify_stream(&mut packet.data_mut())
                };

                if let Err(err) = self.sink.write(&packet.data()) {
                    error!("Could not write audio: {}", err);
                    self.stop_sink();
                }
            }

            None => {
                self.stop_sink();
                self.state.playing_to_end_of_track();
            }
        }
    }

    fn handle_command(&mut self, cmd: PlayerCommand) {
        debug!("command={:?}", cmd);
        match cmd {
            PlayerCommand::Load(track_id, play, position, end_of_track) => {
                if self.state.is_playing() {
                    self.stop_sink_if_running();
                }

                match self.load_track(track_id, position as i64) {
                    Some(decoder) => {
                        if play {
                            match self.state {
                                PlayerState::Playing { track_id: old_track_id, ..}
                                | PlayerState::EndOfTrack { track_id: old_track_id, .. } =>
                                    self.send_event(PlayerEvent::Changed {
                                        old_track_id: old_track_id,
                                        new_track_id: track_id
                                    }),
                                _ => self.send_event(PlayerEvent::Started { track_id }),
                            }

                            self.start_sink();

                            self.state = PlayerState::Playing {
                                track_id: track_id,
                                decoder: decoder,
                                end_of_track: end_of_track,
                            };
                        } else {
                            self.state = PlayerState::Paused {
                                track_id: track_id,
                                decoder: decoder,
                                end_of_track: end_of_track,
                            };
                            match self.state {
                                PlayerState::Playing { track_id: old_track_id, ..}
                                | PlayerState::EndOfTrack { track_id: old_track_id, .. } =>
                                    self.send_event(PlayerEvent::Changed {
                                        old_track_id: old_track_id,
                                        new_track_id: track_id
                                    }),
                                _ => (),
                            }
                            self.send_event(PlayerEvent::Stopped { track_id });
                        }
                    }

                    None => {
                        let _ = end_of_track.send(());
                    }
                }
            }

            PlayerCommand::Seek(position) => {
                if let Some(decoder) = self.state.decoder() {
                    match decoder.seek(position as i64) {
                        Ok(_) => (),
                        Err(err) => error!("Vorbis error: {:?}", err),
                    }
                } else {
                    warn!("Player::seek called from invalid state");
                }
            }

            PlayerCommand::Play => {
                if let PlayerState::Paused { track_id, .. } = self.state {
                    self.state.paused_to_playing();

                    self.send_event(PlayerEvent::Started { track_id });
                    self.start_sink();
                } else {
                    warn!("Player::play called from invalid state");
                }
            }

            PlayerCommand::Pause => {
                if let PlayerState::Playing { track_id, .. } = self.state {
                    self.state.playing_to_paused();

                    self.stop_sink_if_running();
                    self.send_event(PlayerEvent::Stopped { track_id });
                } else {
                    warn!("Player::pause called from invalid state");
                }
            }

            PlayerCommand::Stop => {
                match self.state {
                    PlayerState::Playing { track_id, .. }
                    | PlayerState::Paused { track_id, .. }
                    | PlayerState::EndOfTrack { track_id } => {
                        self.stop_sink_if_running();
                        self.send_event(PlayerEvent::Stopped { track_id });
                        self.state = PlayerState::Stopped;
                    },
                    PlayerState::Stopped => {
                        warn!("Player::stop called from invalid state");
                    }
                    PlayerState::Invalid => panic!("invalid state"),
                }
            }
        }
    }

    fn send_event(&mut self, event: PlayerEvent) {
        let _ = self.event_sender.unbounded_send(event.clone());
    }

    fn find_available_alternative<'a>(&self, track: &'a Track) -> Option<Cow<'a, Track>> {
        if track.available {
            Some(Cow::Borrowed(track))
        } else {
            let alternatives = track.alternatives
                .iter()
                .map(|alt_id| {
                    Track::get(&self.session, *alt_id)
                });
            let alternatives = future::join_all(alternatives).wait().unwrap();

            alternatives.into_iter().find(|alt| alt.available).map(Cow::Owned)
        }
    }

    fn load_track(&self, track_id: SpotifyId, position: i64) -> Option<Decoder> {
        let track = Track::get(&self.session, track_id).wait().unwrap();

        info!("Loading track \"{}\"", track.name);

        let track = match self.find_available_alternative(&track) {
            Some(track) => track,
            None => {
                warn!("Track \"{}\" is not available", track.name);
                return None;
            }
        };

        let format = match self.config.bitrate {
            Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96,
            Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160,
            Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320,
        };

        let file_id = match track.files.get(&format) {
            Some(&file_id) => file_id,
            None => {
                warn!("Track \"{}\" is not available in format {:?}", track.name, format);
                return None;
            }
        };

        let key = self.session.audio_key().request(track.id, file_id).wait().unwrap();

        let encrypted_file = AudioFile::open(&self.session, file_id).wait().unwrap();
        let audio_file = Subfile::new(AudioDecrypt::new(key, encrypted_file), 0xa7);

        let mut decoder = VorbisDecoder::new(audio_file).unwrap();

        match decoder.seek(position) {
            Ok(_) => (),
            Err(err) => error!("Vorbis error: {:?}", err),
        }

        info!("Track \"{}\" loaded", track.name);

        Some(decoder)
    }
}

impl Drop for PlayerInternal {
    fn drop(&mut self) {
        debug!("drop Player[{}]", self.session.session_id());
    }
}

impl ::std::fmt::Debug for PlayerCommand {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            PlayerCommand::Load(track, play, position, _) => {
                f.debug_tuple("Load")
                 .field(&track)
                 .field(&play)
                 .field(&position)
                 .finish()
            }
            PlayerCommand::Play => {
                f.debug_tuple("Play").finish()
            }
            PlayerCommand::Pause => {
                f.debug_tuple("Pause").finish()
            }
            PlayerCommand::Stop => {
                f.debug_tuple("Stop").finish()
            }
            PlayerCommand::Seek(position) => {
                f.debug_tuple("Seek")
                 .field(&position)
                 .finish()
            }
        }
    }
}

struct Subfile<T: Read + Seek> {
    stream: T,
    offset: u64,
}

impl<T: Read + Seek> Subfile<T> {
    pub fn new(mut stream: T, offset: u64) -> Subfile<T> {
        stream.seek(SeekFrom::Start(offset)).unwrap();
        Subfile {
            stream: stream,
            offset: offset,
        }
    }
}

impl<T: Read + Seek> Read for Subfile<T> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.stream.read(buf)
    }
}

impl<T: Read + Seek> Seek for Subfile<T> {
    fn seek(&mut self, mut pos: SeekFrom) -> Result<u64> {
        pos = match pos {
            SeekFrom::Start(offset) => SeekFrom::Start(offset + self.offset),
            x => x,
        };

        let newpos = try!(self.stream.seek(pos));
        if newpos > self.offset {
            Ok(newpos - self.offset)
        } else {
            Ok(0)
        }
    }
}
<commit_msg>Assignment instead of mem::repalce()<commit_after>use futures::sync::oneshot;
use futures::{future, Future};
use futures;
use std;
use std::borrow::Cow;
use std::io::{Read, Seek, SeekFrom, Result};
use std::mem;
use std::sync::mpsc::{RecvError, TryRecvError, RecvTimeoutError};
use std::thread;
use std::time::Duration;

use config::{Bitrate, PlayerConfig};
use core::session::Session;
use core::spotify_id::SpotifyId;

use audio_backend::Sink;
use audio::{AudioFile, AudioDecrypt};
use audio::{VorbisDecoder, VorbisPacket};
use metadata::{FileFormat, Track, Metadata};
use mixer::AudioFilter;

pub struct Player {
    commands: Option<std::sync::mpsc::Sender<PlayerCommand>>,
    thread_handle: Option<thread::JoinHandle<()>>,
}

struct PlayerInternal {
    session: Session,
    config: PlayerConfig,
    commands: std::sync::mpsc::Receiver<PlayerCommand>,

    state: PlayerState,
    sink: Box<Sink>,
    sink_running: bool,
    audio_filter: Option<Box<AudioFilter + Send>>,
    event_sender: futures::sync::mpsc::UnboundedSender<PlayerEvent>,
}

enum PlayerCommand {
    Load(SpotifyId, bool, u32, oneshot::Sender<()>),
    Play,
    Pause,
    Stop,
    Seek(u32),
}

#[derive(Debug, Clone)]
pub enum PlayerEvent {
    Started {
        track_id: SpotifyId,
    },

    Changed {
        old_track_id: SpotifyId,
        new_track_id: SpotifyId,
    },

    Stopped {
        track_id: SpotifyId,
    }
}

type PlayerEventChannel = futures::sync::mpsc::UnboundedReceiver<PlayerEvent>;
impl Player {
    pub fn new<F>(config: PlayerConfig, session: Session,
                  audio_filter: Option<Box<AudioFilter + Send>>,
                  sink_builder: F) -> (Player, PlayerEventChannel)
        where F: FnOnce() -> Box<Sink> + Send + 'static
    {
        let (cmd_tx, cmd_rx) = std::sync::mpsc::channel();
        let (event_sender, event_receiver) = futures::sync::mpsc::unbounded();

        let handle = thread::spawn(move || {
            debug!("new Player[{}]", session.session_id());

            let internal = PlayerInternal {
                session: session,
                config: config,
                commands: cmd_rx,

                state: PlayerState::Stopped,
                sink: sink_builder(),
                sink_running: false,
                audio_filter: audio_filter,
                event_sender: event_sender,
            };

            internal.run();
        });

        (Player { commands: Some(cmd_tx), thread_handle: Some(handle) },
         event_receiver)
    }

    fn command(&self, cmd: PlayerCommand) {
        self.commands.as_ref().unwrap().send(cmd).unwrap();
    }

    pub fn load(&self, track: SpotifyId, start_playing: bool, position_ms: u32)
        -> oneshot::Receiver<()>
    {
        let (tx, rx) = oneshot::channel();
        self.command(PlayerCommand::Load(track, start_playing, position_ms, tx));

        rx
    }

    pub fn play(&self) {
        self.command(PlayerCommand::Play)
    }

    pub fn pause(&self) {
        self.command(PlayerCommand::Pause)
    }

    pub fn stop(&self) {
        self.command(PlayerCommand::Stop)
    }

    pub fn seek(&self, position_ms: u32) {
        self.command(PlayerCommand::Seek(position_ms));
    }
}

impl Drop for Player {
    fn drop(&mut self) {
        debug!("Shutting down player thread ...");
        self.commands = None;
        if let Some(handle) = self.thread_handle.take() {
            match handle.join() {
                Ok(_) => (),
                Err(_) => error!("Player thread panicked!")
            }
        }
    }
}

type Decoder = VorbisDecoder<Subfile<AudioDecrypt<AudioFile>>>;
enum PlayerState {
    Stopped,
    Paused {
        track_id: SpotifyId,
        decoder: Decoder,
        end_of_track: oneshot::Sender<()>,
    },
    Playing {
        track_id: SpotifyId,
        decoder: Decoder,
        end_of_track: oneshot::Sender<()>,
    },
    EndOfTrack { track_id: SpotifyId },
    Invalid,
}

impl PlayerState {
    fn is_playing(&self) -> bool {
        use self::PlayerState::*;
        match *self {
            Stopped | EndOfTrack { .. } | Paused { .. } => false,
            Playing { .. } => true,
            Invalid => panic!("invalid state"),
        }
    }

    fn decoder(&mut self) -> Option<&mut Decoder> {
        use self::PlayerState::*;
        match *self {
            Stopped | EndOfTrack { .. } => None,
            Paused { ref mut decoder, .. } |
            Playing { ref mut decoder, .. } => Some(decoder),
            Invalid => panic!("invalid state"),
        }
    }

    fn playing_to_end_of_track(&mut self) {
        use self::PlayerState::*;
        match mem::replace(self, Invalid) {
            Playing { track_id, end_of_track, ..} => {
                end_of_track.send(());
                *self = EndOfTrack { track_id };
            },
            _ => panic!("Called playing_to_end_of_track in non-playing state.")
        }
    }

    fn paused_to_playing(&mut self) {
        use self::PlayerState::*;
        match ::std::mem::replace(self, Invalid) {
            Paused { decoder, end_of_track, track_id } => {
                *self = Playing {
                    decoder: decoder,
                    end_of_track: end_of_track,
                    track_id: track_id,
                };
            }
            _ => panic!("invalid state"),
        }
    }

    fn playing_to_paused(&mut self) {
        use self::PlayerState::*;
        match ::std::mem::replace(self, Invalid) {
            Playing { decoder, end_of_track, track_id } => {
                *self = Paused {
                    decoder: decoder,
                    end_of_track: end_of_track,
                    track_id: track_id,
                };
            }
            _ => panic!("invalid state"),
        }
    }
}

impl PlayerInternal {
    fn run(mut self) {
        loop {
            let cmd = if self.state.is_playing() {
                if self.sink_running
                {
                    match self.commands.try_recv() {
                        Ok(cmd) => Some(cmd),
                        Err(TryRecvError::Empty) => None,
                        Err(TryRecvError::Disconnected) => return,
                    }
                }
                else
                {
                    match self.commands.recv_timeout(Duration::from_secs(5)) {
                        Ok(cmd) => Some(cmd),
                        Err(RecvTimeoutError::Timeout) => None,
                        Err(RecvTimeoutError::Disconnected) => return,
                    }
                }
            } else {
                match self.commands.recv() {
                    Ok(cmd) => Some(cmd),
                    Err(RecvError) => return,
                }
            };

            if let Some(cmd) = cmd {
                self.handle_command(cmd);
            }

            if self.state.is_playing() && ! self.sink_running {
                self.start_sink();
            }

            if self.sink_running {
                let packet = if let PlayerState::Playing { ref mut decoder, .. } = self.state {
                    Some(decoder.next_packet().expect("Vorbis error"))
                } else {
                    None
                };

                if let Some(packet) = packet {
                    self.handle_packet(packet);
                }
            }
        }
    }

    fn start_sink(&mut self) {
        match self.sink.start() {
            Ok(()) => self.sink_running = true,
            Err(err) => error!("Could not start audio: {}", err),
        }
    }

    fn stop_sink_if_running(&mut self) {
        if self.sink_running {
            self.stop_sink();
        }
    }

    fn stop_sink(&mut self) {
        self.sink.stop().unwrap();
        self.sink_running = false;
    }

    fn handle_packet(&mut self, packet: Option<VorbisPacket>) {
        match packet {
            Some(mut packet) => {
                if let Some(ref editor) = self.audio_filter {
                    editor.modify_stream(&mut packet.data_mut())
                };

                if let Err(err) = self.sink.write(&packet.data()) {
                    error!("Could not write audio: {}", err);
                    self.stop_sink();
                }
            }

            None => {
                self.stop_sink();
                self.state.playing_to_end_of_track();
            }
        }
    }

    fn handle_command(&mut self, cmd: PlayerCommand) {
        debug!("command={:?}", cmd);
        match cmd {
            PlayerCommand::Load(track_id, play, position, end_of_track) => {
                if self.state.is_playing() {
                    self.stop_sink_if_running();
                }

                match self.load_track(track_id, position as i64) {
                    Some(decoder) => {
                        if play {
                            match self.state {
                                PlayerState::Playing { track_id: old_track_id, ..}
                                | PlayerState::EndOfTrack { track_id: old_track_id, .. } =>
                                    self.send_event(PlayerEvent::Changed {
                                        old_track_id: old_track_id,
                                        new_track_id: track_id
                                    }),
                                _ => self.send_event(PlayerEvent::Started { track_id }),
                            }

                            self.start_sink();

                            self.state = PlayerState::Playing {
                                track_id: track_id,
                                decoder: decoder,
                                end_of_track: end_of_track,
                            };
                        } else {
                            self.state = PlayerState::Paused {
                                track_id: track_id,
                                decoder: decoder,
                                end_of_track: end_of_track,
                            };
                            match self.state {
                                PlayerState::Playing { track_id: old_track_id, ..}
                                | PlayerState::EndOfTrack { track_id: old_track_id, .. } =>
                                    self.send_event(PlayerEvent::Changed {
                                        old_track_id: old_track_id,
                                        new_track_id: track_id
                                    }),
                                _ => (),
                            }
                            self.send_event(PlayerEvent::Stopped { track_id });
                        }
                    }

                    None => {
                        let _ = end_of_track.send(());
                    }
                }
            }

            PlayerCommand::Seek(position) => {
                if let Some(decoder) = self.state.decoder() {
                    match decoder.seek(position as i64) {
                        Ok(_) => (),
                        Err(err) => error!("Vorbis error: {:?}", err),
                    }
                } else {
                    warn!("Player::seek called from invalid state");
                }
            }

            PlayerCommand::Play => {
                if let PlayerState::Paused { track_id, .. } = self.state {
                    self.state.paused_to_playing();

                    self.send_event(PlayerEvent::Started { track_id });
                    self.start_sink();
                } else {
                    warn!("Player::play called from invalid state");
                }
            }

            PlayerCommand::Pause => {
                if let PlayerState::Playing { track_id, .. } = self.state {
                    self.state.playing_to_paused();

                    self.stop_sink_if_running();
                    self.send_event(PlayerEvent::Stopped { track_id });
                } else {
                    warn!("Player::pause called from invalid state");
                }
            }

            PlayerCommand::Stop => {
                match self.state {
                    PlayerState::Playing { track_id, .. }
                    | PlayerState::Paused { track_id, .. }
                    | PlayerState::EndOfTrack { track_id } => {
                        self.stop_sink_if_running();
                        self.send_event(PlayerEvent::Stopped { track_id });
                        self.state = PlayerState::Stopped;
                    },
                    PlayerState::Stopped => {
                        warn!("Player::stop called from invalid state");
                    }
                    PlayerState::Invalid => panic!("invalid state"),
                }
            }
        }
    }

    fn send_event(&mut self, event: PlayerEvent) {
        let _ = self.event_sender.unbounded_send(event.clone());
    }

    fn find_available_alternative<'a>(&self, track: &'a Track) -> Option<Cow<'a, Track>> {
        if track.available {
            Some(Cow::Borrowed(track))
        } else {
            let alternatives = track.alternatives
                .iter()
                .map(|alt_id| {
                    Track::get(&self.session, *alt_id)
                });
            let alternatives = future::join_all(alternatives).wait().unwrap();

            alternatives.into_iter().find(|alt| alt.available).map(Cow::Owned)
        }
    }

    fn load_track(&self, track_id: SpotifyId, position: i64) -> Option<Decoder> {
        let track = Track::get(&self.session, track_id).wait().unwrap();

        info!("Loading track \"{}\"", track.name);

        let track = match self.find_available_alternative(&track) {
            Some(track) => track,
            None => {
                warn!("Track \"{}\" is not available", track.name);
                return None;
            }
        };

        let format = match self.config.bitrate {
            Bitrate::Bitrate96 => FileFormat::OGG_VORBIS_96,
            Bitrate::Bitrate160 => FileFormat::OGG_VORBIS_160,
            Bitrate::Bitrate320 => FileFormat::OGG_VORBIS_320,
        };

        let file_id = match track.files.get(&format) {
            Some(&file_id) => file_id,
            None => {
                warn!("Track \"{}\" is not available in format {:?}", track.name, format);
                return None;
            }
        };

        let key = self.session.audio_key().request(track.id, file_id).wait().unwrap();

        let encrypted_file = AudioFile::open(&self.session, file_id).wait().unwrap();
        let audio_file = Subfile::new(AudioDecrypt::new(key, encrypted_file), 0xa7);

        let mut decoder = VorbisDecoder::new(audio_file).unwrap();

        match decoder.seek(position) {
            Ok(_) => (),
            Err(err) => error!("Vorbis error: {:?}", err),
        }

        info!("Track \"{}\" loaded", track.name);

        Some(decoder)
    }
}

impl Drop for PlayerInternal {
    fn drop(&mut self) {
        debug!("drop Player[{}]", self.session.session_id());
    }
}

impl ::std::fmt::Debug for PlayerCommand {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            PlayerCommand::Load(track, play, position, _) => {
                f.debug_tuple("Load")
                 .field(&track)
                 .field(&play)
                 .field(&position)
                 .finish()
            }
            PlayerCommand::Play => {
                f.debug_tuple("Play").finish()
            }
            PlayerCommand::Pause => {
                f.debug_tuple("Pause").finish()
            }
            PlayerCommand::Stop => {
                f.debug_tuple("Stop").finish()
            }
            PlayerCommand::Seek(position) => {
                f.debug_tuple("Seek")
                 .field(&position)
                 .finish()
            }
        }
    }
}

struct Subfile<T: Read + Seek> {
    stream: T,
    offset: u64,
}

impl<T: Read + Seek> Subfile<T> {
    pub fn new(mut stream: T, offset: u64) -> Subfile<T> {
        stream.seek(SeekFrom::Start(offset)).unwrap();
        Subfile {
            stream: stream,
            offset: offset,
        }
    }
}

impl<T: Read + Seek> Read for Subfile<T> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.stream.read(buf)
    }
}

impl<T: Read + Seek> Seek for Subfile<T> {
    fn seek(&mut self, mut pos: SeekFrom) -> Result<u64> {
        pos = match pos {
            SeekFrom::Start(offset) => SeekFrom::Start(offset + self.offset),
            x => x,
        };

        let newpos = try!(self.stream.seek(pos));
        if newpos > self.offset {
            Ok(newpos - self.offset)
        } else {
            Ok(0)
        }
    }
}
<|endoftext|>


<commit_before>use yaml_rust::Yaml;
use command::{Command, Session, SendKeys, Split, Layout, Window, Attach, KillWindow};
use rand::random;

#[cfg(test)] use yaml_rust::{YamlLoader};

pub fn main(yaml_string: &Vec<Yaml>, project_name: &String) -> Vec<Command> {
    let mut commands: Vec<Command> = vec!();
    let tmp_window_name = format!("muxed_first_window_{}", random::<u16>().to_string());

    commands.push(Command::Session(Session{name: project_name.clone(), tmp_window_name: tmp_window_name.clone()}));

    for doc in yaml_string {
        let root = match doc["root"].as_str() {
            Some(x) => Some(x.to_string()),
            None    => None
        };

        let windows = doc["windows"].as_vec().expect("No Windows have been defined.");
        for (i, window) in windows.iter().enumerate() {
            match window {
                &Yaml::Hash(ref h)  => {
                    for (k, v) in h {
                        if v.as_hash().is_some() {
                            commands.push(Command::Window(Window{session_name: format!("{}:{}", project_name.clone(), i+1), name: k.as_str().unwrap().to_string(), root: root.clone()}));
                            commands.append(&mut pane_matcher(project_name.clone(), v, root.clone(), k.as_str().unwrap().to_string()));
                        } else {
                            commands.push(Command::Window(Window{session_name: format!("{}:{}", project_name.clone(), i+1), name: k.as_str().unwrap().to_string(), root: root.clone()}));
                            commands.push(Command::SendKeys(SendKeys{target: format!("{}:{}", project_name, k.as_str().unwrap().to_string()).to_string(), exec: v.as_str().expect("Bad exec command").to_string()}));
                        }
                    }
                },
                &Yaml::String(ref s) => {
                    commands.push(Command::Window(Window{session_name: format!("{}:{}", project_name.clone(), i+1), name: s.clone(), root: root.clone()}))
                },
                &Yaml::Integer(ref s) => {
                    commands.push(Command::Window(Window{session_name: format!("{}:{}", project_name.clone(), i+1), name: s.to_string(), root: root.clone()}))
                },
                _ => panic!("Muxed config file formatting isn't recognized.")
            };
        };
    };

    commands.push(Command::KillWindow(KillWindow{name: format!("{}:{}", project_name.clone(), tmp_window_name.clone())}));
    commands.push(Command::Attach(Attach{name: project_name.clone()}));
    commands
}

fn pane_matcher(session: String, panes: &Yaml, root: Option<String>, window: String) -> Vec<Command> {
    let mut commands = vec!();
    let panes2 = panes["panes"].as_vec().expect("Something is wrong with panes.");

    for (i, pane) in panes2.iter().enumerate() {
        if i < (panes2.len()-1) {
            commands.push(Command::Split(Split{target: format!("{}:{}.{}", session, window, i.to_string()).to_string(), root: root.clone()}));
        };
        commands.push(Command::SendKeys(SendKeys{target: format!("{}:{}.{}", session, window, i).to_string(), exec: pane.as_str().expect("Bad exec command").to_string()}));
    };

    if panes["layout"].as_str().is_some() {
        let layout = panes["layout"].as_str().expect("Bad layout").to_string();
        commands.push(Command::Layout(Layout{target: format!("{}:{}", session, window).to_string(), layout: layout}));
    };

    commands
}

#[test]
pub fn windows_defined_as_array_has_6_commands() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    assert_eq!(main(&yaml, &"muxed".to_string()).len(), 6)
}

#[test]
pub fn windows_defined_as_array_has_1_session() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Session(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn windows_defined_as_array_has_3_windows() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Window(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 3)
}

#[test]
pub fn windows_defined_as_array_has_1_attach() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Attach(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn windows_with_integer_names() {
    let s = "---
windows: [1, 'vim', 3]
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    assert_eq!(main(&yaml, &"muxed".to_string()).len(), 6)
}

#[test]
pub fn windows_as_list() {
    let s = "---
windows:
  - cargo: ''
  - vim: ''
  - git: ''
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let commands = main(&yaml, &"muxed".to_string());
    assert_eq!(commands.len(), 9)
}

#[test]
pub fn panes_array_has_8_commands() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let commands = main(&yaml, &"muxed".to_string());
    assert_eq!(commands.len(), 8)
}

#[test]
pub fn panes_array_has_1_split() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";

    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Split(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn panes_array_has_1_layout() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";

    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Layout(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn panes_array_has_1_window() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";

    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Window(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn panes_array_has_1_session() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";

    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Session(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

//#[test]
//pub fn panes_command_execs_array() {
//    let s = "---
//windows:
//  - editor:
//      layout: 'main-vertical'
//      panes: ['vim', 'guard']
//";
//    let yaml = YamlLoader::load_from_str(s).unwrap();
//    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
//      &Command::SendKeys(_) => true,
//      _ => false
//    }).collect();
//
//    assert_eq!(remains.len(), 2);
//    assert_eq!(remains[0].exec, "vim");
//    assert_eq!(remains[1].exec, "guard")
//}
<commit_msg>Strings passed in to format! functions don't need to be cloned<commit_after>use yaml_rust::Yaml;
use command::{Command, Session, SendKeys, Split, Layout, Window, Attach, KillWindow};
use rand::random;

#[cfg(test)] use yaml_rust::{YamlLoader};

pub fn main(yaml_string: &Vec<Yaml>, project_name: &String) -> Vec<Command> {
    let mut commands: Vec<Command> = vec!();
    let tmp_window_name = format!("muxed_first_window_{}", random::<u16>().to_string());

    commands.push(Command::Session(Session{name: project_name.clone(), tmp_window_name: tmp_window_name.clone()}));

    for doc in yaml_string {
        let root = match doc["root"].as_str() {
            Some(x) => Some(x.to_string()),
            None    => None
        };

        let windows = doc["windows"].as_vec().expect("No Windows have been defined.");
        for (i, window) in windows.iter().enumerate() {
            match window {
                &Yaml::Hash(ref h)  => {
                    for (k, v) in h {
                        if v.as_hash().is_some() {
                            commands.push(Command::Window(Window{session_name: format!("{}:{}", project_name, i+1), name: k.as_str().unwrap().to_string(), root: root.clone()}));
                            commands.append(&mut pane_matcher(&project_name, v, &root, k.as_str().unwrap().to_string()));
                        } else {
                            commands.push(Command::Window(Window{session_name: format!("{}:{}", project_name, i+1), name: k.as_str().unwrap().to_string(), root: root.clone()}));
                            commands.push(Command::SendKeys(SendKeys{target: format!("{}:{}", project_name, k.as_str().unwrap().to_string()).to_string(), exec: v.as_str().expect("Bad exec command").to_string()}));
                        }
                    }
                },
                &Yaml::String(ref s) => {
                    commands.push(Command::Window(Window{session_name: format!("{}:{}", project_name, i+1), name: s.clone(), root: root.clone()}))
                },
                &Yaml::Integer(ref s) => {
                    commands.push(Command::Window(Window{session_name: format!("{}:{}", project_name, i+1), name: s.to_string(), root: root.clone()}))
                },
                _ => panic!("Muxed config file formatting isn't recognized.")
            };
        };
    };

    commands.push(Command::KillWindow(KillWindow{name: format!("{}:{}", project_name, tmp_window_name)}));
    commands.push(Command::Attach(Attach{name: project_name.clone()}));
    commands
}

fn pane_matcher(session: &String, panes: &Yaml, root: &Option<String>, window: String) -> Vec<Command> {
    let mut commands = vec!();
    let panes2 = panes["panes"].as_vec().expect("Something is wrong with panes.");

    for (i, pane) in panes2.iter().enumerate() {
        if i < (panes2.len()-1) {
            commands.push(Command::Split(Split{target: format!("{}:{}.{}", session, window, i.to_string()).to_string(), root: root.clone()}));
        };
        commands.push(Command::SendKeys(SendKeys{target: format!("{}:{}.{}", session, window, i).to_string(), exec: pane.as_str().expect("Bad exec command").to_string()}));
    };

    if panes["layout"].as_str().is_some() {
        let layout = panes["layout"].as_str().expect("Bad layout").to_string();
        commands.push(Command::Layout(Layout{target: format!("{}:{}", session, window).to_string(), layout: layout}));
    };

    commands
}

#[test]
pub fn windows_defined_as_array_has_6_commands() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    assert_eq!(main(&yaml, &"muxed".to_string()).len(), 6)
}

#[test]
pub fn windows_defined_as_array_has_1_session() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Session(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn windows_defined_as_array_has_3_windows() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Window(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 3)
}

#[test]
pub fn windows_defined_as_array_has_1_attach() {
    let s = "---
windows: ['cargo', 'vim', 'git']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Attach(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn windows_with_integer_names() {
    let s = "---
windows: [1, 'vim', 3]
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    assert_eq!(main(&yaml, &"muxed".to_string()).len(), 6)
}

#[test]
pub fn windows_as_list() {
    let s = "---
windows:
  - cargo: ''
  - vim: ''
  - git: ''
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let commands = main(&yaml, &"muxed".to_string());
    assert_eq!(commands.len(), 9)
}

#[test]
pub fn panes_array_has_8_commands() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";
    let yaml = YamlLoader::load_from_str(s).unwrap();
    let commands = main(&yaml, &"muxed".to_string());
    assert_eq!(commands.len(), 8)
}

#[test]
pub fn panes_array_has_1_split() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";

    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Split(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn panes_array_has_1_layout() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";

    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Layout(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn panes_array_has_1_window() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";

    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Window(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

#[test]
pub fn panes_array_has_1_session() {
    let s = "---
windows:
  - editor:
      layout: 'main-vertical'
      panes: ['vim', 'guard']
";

    let yaml = YamlLoader::load_from_str(s).unwrap();
    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
        &Command::Session(_) => true,
        _ => false
    }).collect();

    assert_eq!(remains.len(), 1)
}

//#[test]
//pub fn panes_command_execs_array() {
//    let s = "---
//windows:
//  - editor:
//      layout: 'main-vertical'
//      panes: ['vim', 'guard']
//";
//    let yaml = YamlLoader::load_from_str(s).unwrap();
//    let remains: Vec<Command> = main(&yaml, &"muxed".to_string()).into_iter().filter(|x| match x {
//      &Command::SendKeys(_) => true,
//      _ => false
//    }).collect();
//
//    assert_eq!(remains.len(), 2);
//    assert_eq!(remains[0].exec, "vim");
//    assert_eq!(remains[1].exec, "guard")
//}
<|endoftext|>


<commit_before>use std::iter::{Fuse, Iterator};

use core::{Point, SourceByteRange};

pub struct StmtIndicesIter<'a,I>
    where I: Iterator<Item=SourceByteRange>
{
    src: &'a str,
    it: I,
    pos: Point,
    end: Point
}

impl<'a,I> Iterator for StmtIndicesIter<'a,I>
    where I: Iterator<Item=SourceByteRange>
{
    type Item = SourceByteRange;

    #[inline]
    fn next(&mut self) -> Option<SourceByteRange> {
        let src_bytes = self.src.as_bytes();
        let mut enddelim = b';';
        let mut bracelevel = 0isize;
        let mut parenlevel = 0isize;
        let mut start = self.pos;
        let mut pos = self.pos;

        // loop on all code_chunks until we find a relevant open/close pattern
        loop {
            // do we need the next chunk?
            if self.end == pos {
                // get the next chunk of code
                match self.it.next() {
                    Some((ch_start, ch_end)) => {
                        self.end = ch_end;
                        if start == pos { start = ch_start; }
                        pos = ch_start;
                    }
                    None => {
                        // no more chunks. finished
                        self.pos = pos;
                        return if start < self.end { Some((start, self.end)) }
                               else { None }
                    }
                }
            }

            if start == pos {
                // if this is a new stmt block, skip the whitespace
                for &b in &src_bytes[pos..self.end] {
                    match b {
                        b' ' | b'\r' | b'\n' | b'\t' => { pos += 1; },
                        _ => { break; }
                    }
                }
                start = pos;

                // test attribute   #[foo = bar]
                if pos < self.end && src_bytes[pos] == b'#' {
                    enddelim = b']'
                };
            }

            // iterate through the chunk, looking for stmt end
            for &b in &src_bytes[pos..self.end] {
                pos += 1;

                match b {
                    b'(' => { parenlevel += 1; },
                    b')' => { parenlevel -= 1; },
                    b'{' => {
                        // if we are top level and stmt is not a 'use' or 'let' then
                        // closebrace finishes the stmt
                        if bracelevel == 0 && parenlevel == 0
                            && !(is_a_use_stmt(src_bytes, start, pos) || is_a_let_stmt(src_bytes, start, pos)) {
                            enddelim = b'}';
                        }
                        bracelevel += 1;
                    },
                    b'}' => {
                        // have we reached the end of the scope?
                        if bracelevel == 0 {
                            self.pos = pos;
                            return None;
                        }
                        bracelevel -= 1;
                    },
                    b'!' => {
                        // macro if followed by at least one space or (
                        // FIXME: test with boolean 'not' expression
                        if parenlevel == 0 && bracelevel == 0
                            && pos < self.end && (pos-start) > 1 {
                            match src_bytes[pos] {
                                b' ' | b'\r' | b'\n' | b'\t' | b'('  => {
                                    enddelim = b')';
                                },
                                _ => {}
                            }
                        }
                    }
                    _ => {}
                }

                if enddelim == b && bracelevel == 0 && parenlevel == 0 {
                    self.pos = pos;
                    return Some((start, pos));
                }
            }
        }
    }
}

fn is_a_use_stmt(src_bytes: &[u8], start: Point, pos: Point) -> bool {
    let whitespace = b" {\t\r\n";
    (pos > 3 && &src_bytes[start..start+3] == b"use" &&
     whitespace.contains(&src_bytes[start+3])) ||
    (pos > 7 && &src_bytes[start..(start+7)] == b"pub use" &&
     whitespace.contains(&src_bytes[start+7]))
}

fn is_a_let_stmt(src_bytes: &[u8], start: Point, pos: Point) -> bool {
    let whitespace = b" {\t\r\n";
    pos > 3 && &src_bytes[start..start+3] == b"let" && whitespace.contains(&src_bytes[start+3])
}

impl<'a, I> StmtIndicesIter<'a,I>
    where I: Iterator<Item=SourceByteRange>
{
    pub fn from_parts(src: &str, it: I) -> Fuse<StmtIndicesIter<I>> {
        StmtIndicesIter{ src: src, it: it, pos: 0, end: 0 }.fuse()
    }
}

#[cfg(test)]
mod test {
    use std::iter::Fuse;

    use codecleaner;
    use testutils::{rejustify, slice};

    use super::*;

    fn iter_stmts(src: &str) -> Fuse<StmtIndicesIter<codecleaner::CodeIndicesIter>> {
        let it = codecleaner::code_chunks(src);
        StmtIndicesIter{ src: src, it: it, pos: 0, end: 0 }.fuse()
    }

    #[test]
    fn iterates_single_use_stmts() {
        let src = rejustify("
            use std::Foo; // a comment
            use std::Bar;
        ");

        let mut it = iter_stmts(src.as_ref());
        assert_eq!("use std::Foo;", slice(&src, it.next().unwrap()));
        assert_eq!("use std::Bar;", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_use_stmt_over_two_lines() {
        let src = rejustify("
        use std::{Foo,
                  Bar}; // a comment
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("use std::{Foo,
              Bar};", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_use_stmt_without_the_prefix() {
        let src = rejustify("
        pub use {Foo,
                 Bar}; // this is also legit apparently
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("pub use {Foo,
             Bar};", slice(&src, it.next().unwrap())
        );
    }

    #[test]
    fn iterates_while_stmt() {
        let src = rejustify("
            while self.pos < 3 { }
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("while self.pos < 3 { }", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_lambda_arg() {
        let src = rejustify("
            myfn(|n|{});
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("myfn(|n|{});", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_macro() {
        let src = "
        mod foo;
        macro_rules! otry(
            ($e:expr) => (match $e { Some(e) => e, None => return })
        )
        mod bar;
        ";
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("mod foo;", slice(&src, it.next().unwrap()));
        assert_eq!("macro_rules! otry(
            ($e:expr) => (match $e { Some(e) => e, None => return })
        )", slice(&src, it.next().unwrap()));
        assert_eq!("mod bar;", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_macro_invocation() {
        let src = "
            mod foo;
            local_data_key!(local_stdout: Box<Writer + Send>)  // no ';'
            mod bar;
        ";
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("mod foo;", slice(&src, it.next().unwrap()));
        assert_eq!("local_data_key!(local_stdout: Box<Writer + Send>)", slice(&src, it.next().unwrap()));
        assert_eq!("mod bar;", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_if_else_stmt() {
        let src = "
            if self.pos < 3 { } else { }
        ";
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("if self.pos < 3 { }", slice(&src, it.next().unwrap()));
        assert_eq!("else { }", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_inner_scope() {
        let src = &"
        while(self.pos < 3 {
            let a = 35;
            return a + 35;  // should iterate this
        }
        {
            b = foo;       // but not this
        }
        "[29..];

        let mut it = iter_stmts(src.as_ref());

        assert_eq!("let a = 35;", slice(&src, it.next().unwrap()));
        assert_eq!("return a + 35;", slice(&src, it.next().unwrap()));
        assert_eq!(None, it.next());
    }

    #[test]
    fn iterates_module_attribute() {
        let src = rejustify("
            #![license = \"BSD\"]
            #[test]
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("#![license = \"BSD\"]", slice(&src, it.next().unwrap()));
        assert_eq!("#[test]", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_half_open_subscope_if_is_the_last_thing() {
        let src = "
            let something = 35;
            while self.pos < 3 {
            let a = 35;
            return a + 35;  // should iterate this
        ";

        let mut it = iter_stmts(src.as_ref());
        assert_eq!("let something = 35;", slice(&src, it.next().unwrap()));
        assert_eq!("while self.pos < 3 {
            let a = 35;
            return a + 35;  // should iterate this
        ", slice(&src, it.next().unwrap()));
    }

}
<commit_msg>check array bracket (#841)<commit_after>use std::iter::{Fuse, Iterator};

use core::{Point, SourceByteRange};

pub struct StmtIndicesIter<'a,I>
    where I: Iterator<Item=SourceByteRange>
{
    src: &'a str,
    it: I,
    pos: Point,
    end: Point
}

impl<'a,I> Iterator for StmtIndicesIter<'a,I>
    where I: Iterator<Item=SourceByteRange>
{
    type Item = SourceByteRange;

    #[inline]
    fn next(&mut self) -> Option<SourceByteRange> {
        let src_bytes = self.src.as_bytes();
        let mut enddelim = b';';
        let mut bracelevel = 0isize;
        let mut parenlevel = 0isize;
        let mut bracketlevel = 0isize;
        let mut start = self.pos;
        let mut pos = self.pos;

        // loop on all code_chunks until we find a relevant open/close pattern
        loop {
            // do we need the next chunk?
            if self.end == pos {
                // get the next chunk of code
                match self.it.next() {
                    Some((ch_start, ch_end)) => {
                        self.end = ch_end;
                        if start == pos { start = ch_start; }
                        pos = ch_start;
                    }
                    None => {
                        // no more chunks. finished
                        self.pos = pos;
                        return if start < self.end { Some((start, self.end)) }
                               else { None }
                    }
                }
            }

            if start == pos {
                // if this is a new stmt block, skip the whitespace
                for &b in &src_bytes[pos..self.end] {
                    match b {
                        b' ' | b'\r' | b'\n' | b'\t' => { pos += 1; },
                        _ => { break; }
                    }
                }
                start = pos;

                // test attribute   #[foo = bar]
                if pos < self.end && src_bytes[pos] == b'#' {
                    enddelim = b']'
                };
            }

            // iterate through the chunk, looking for stmt end
            for &b in &src_bytes[pos..self.end] {
                pos += 1;

                match b {
                    b'(' => { parenlevel += 1; },
                    b')' => { parenlevel -= 1; },
                    b'[' => { bracketlevel += 1; },
                    b']' => { bracketlevel -= 1; },
                    b'{' => {
                        // if we are top level and stmt is not a 'use' or 'let' then
                        // closebrace finishes the stmt
                        if bracelevel == 0 && parenlevel == 0
                            && !(is_a_use_stmt(src_bytes, start, pos) || is_a_let_stmt(src_bytes, start, pos)) {
                            enddelim = b'}';
                        }
                        bracelevel += 1;
                    },
                    b'}' => {
                        // have we reached the end of the scope?
                        if bracelevel == 0 {
                            self.pos = pos;
                            return None;
                        }
                        bracelevel -= 1;
                    },
                    b'!' => {
                        // macro if followed by at least one space or (
                        // FIXME: test with boolean 'not' expression
                        if parenlevel == 0 && bracelevel == 0
                            && pos < self.end && (pos-start) > 1 {
                            match src_bytes[pos] {
                                b' ' | b'\r' | b'\n' | b'\t' | b'('  => {
                                    enddelim = b')';
                                },
                                _ => {}
                            }
                        }
                    }
                    _ => {}
                }

                if enddelim == b && bracelevel == 0 && parenlevel == 0 && bracketlevel == 0 {
                    self.pos = pos;
                    return Some((start, pos));
                }
            }
        }
    }
}

fn is_a_use_stmt(src_bytes: &[u8], start: Point, pos: Point) -> bool {
    let whitespace = b" {\t\r\n";
    (pos > 3 && &src_bytes[start..start+3] == b"use" &&
     whitespace.contains(&src_bytes[start+3])) ||
    (pos > 7 && &src_bytes[start..(start+7)] == b"pub use" &&
     whitespace.contains(&src_bytes[start+7]))
}

fn is_a_let_stmt(src_bytes: &[u8], start: Point, pos: Point) -> bool {
    let whitespace = b" {\t\r\n";
    pos > 3 && &src_bytes[start..start+3] == b"let" && whitespace.contains(&src_bytes[start+3])
}

impl<'a, I> StmtIndicesIter<'a,I>
    where I: Iterator<Item=SourceByteRange>
{
    pub fn from_parts(src: &str, it: I) -> Fuse<StmtIndicesIter<I>> {
        StmtIndicesIter{ src: src, it: it, pos: 0, end: 0 }.fuse()
    }
}

#[cfg(test)]
mod test {
    use std::iter::Fuse;

    use codecleaner;
    use testutils::{rejustify, slice};

    use super::*;

    fn iter_stmts(src: &str) -> Fuse<StmtIndicesIter<codecleaner::CodeIndicesIter>> {
        let it = codecleaner::code_chunks(src);
        StmtIndicesIter{ src: src, it: it, pos: 0, end: 0 }.fuse()
    }

    #[test]
    fn iterates_single_use_stmts() {
        let src = rejustify("
            use std::Foo; // a comment
            use std::Bar;
        ");

        let mut it = iter_stmts(src.as_ref());
        assert_eq!("use std::Foo;", slice(&src, it.next().unwrap()));
        assert_eq!("use std::Bar;", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_array_stmts() {
        let src = rejustify("
            let a: [i32; 2] = [1, 2];
            let b = [[0], [1], [2]];
            let c = ([1, 2, 3])[1];
        ");

        let mut it = iter_stmts(src.as_ref());
        assert_eq!("let a: [i32; 2] = [1, 2];", slice(&src, it.next().unwrap()));
        assert_eq!("let b = [[0], [1], [2]];", slice(&src, it.next().unwrap()));
        assert_eq!("let c = ([1, 2, 3])[1];", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_use_stmt_over_two_lines() {
        let src = rejustify("
        use std::{Foo,
                  Bar}; // a comment
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("use std::{Foo,
              Bar};", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_use_stmt_without_the_prefix() {
        let src = rejustify("
        pub use {Foo,
                 Bar}; // this is also legit apparently
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("pub use {Foo,
             Bar};", slice(&src, it.next().unwrap())
        );
    }

    #[test]
    fn iterates_while_stmt() {
        let src = rejustify("
            while self.pos < 3 { }
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("while self.pos < 3 { }", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_lambda_arg() {
        let src = rejustify("
            myfn(|n|{});
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("myfn(|n|{});", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_macro() {
        let src = "
        mod foo;
        macro_rules! otry(
            ($e:expr) => (match $e { Some(e) => e, None => return })
        )
        mod bar;
        ";
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("mod foo;", slice(&src, it.next().unwrap()));
        assert_eq!("macro_rules! otry(
            ($e:expr) => (match $e { Some(e) => e, None => return })
        )", slice(&src, it.next().unwrap()));
        assert_eq!("mod bar;", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_macro_invocation() {
        let src = "
            mod foo;
            local_data_key!(local_stdout: Box<Writer + Send>)  // no ';'
            mod bar;
        ";
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("mod foo;", slice(&src, it.next().unwrap()));
        assert_eq!("local_data_key!(local_stdout: Box<Writer + Send>)", slice(&src, it.next().unwrap()));
        assert_eq!("mod bar;", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_if_else_stmt() {
        let src = "
            if self.pos < 3 { } else { }
        ";
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("if self.pos < 3 { }", slice(&src, it.next().unwrap()));
        assert_eq!("else { }", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_inner_scope() {
        let src = &"
        while(self.pos < 3 {
            let a = 35;
            return a + 35;  // should iterate this
        }
        {
            b = foo;       // but not this
        }
        "[29..];

        let mut it = iter_stmts(src.as_ref());

        assert_eq!("let a = 35;", slice(&src, it.next().unwrap()));
        assert_eq!("return a + 35;", slice(&src, it.next().unwrap()));
        assert_eq!(None, it.next());
    }

    #[test]
    fn iterates_module_attribute() {
        let src = rejustify("
            #![license = \"BSD\"]
            #[test]
        ");
        let mut it = iter_stmts(src.as_ref());
        assert_eq!("#![license = \"BSD\"]", slice(&src, it.next().unwrap()));
        assert_eq!("#[test]", slice(&src, it.next().unwrap()));
    }

    #[test]
    fn iterates_half_open_subscope_if_is_the_last_thing() {
        let src = "
            let something = 35;
            while self.pos < 3 {
            let a = 35;
            return a + 35;  // should iterate this
        ";

        let mut it = iter_stmts(src.as_ref());
        assert_eq!("let something = 35;", slice(&src, it.next().unwrap()));
        assert_eq!("while self.pos < 3 {
            let a = 35;
            return a + 35;  // should iterate this
        ", slice(&src, it.next().unwrap()));
    }

}
<|endoftext|>


<commit_before>// #![feature(phase)]
// #[phase(plugin, link)] extern crate log;

use racer::codecleaner::{code_chunks,CodeIndicesIter};
// use codecleaner::{code_chunks,CodeIndicesIter};
// mod codecleaner;

#[cfg(test)] use racer::testutils::{rejustify, slice};

pub struct StmtIndicesIter<'a> {
    src: &'a str,
    it: CodeIndicesIter<'a>,
    pos: usize,
    end: usize
}

impl<'a> Iterator for StmtIndicesIter<'a> {
    type Item = (usize, usize);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize)> {

        let src_bytes = self.src.as_bytes();
        let mut enddelim = b';';
        let mut bracelevel = 02;
        let mut parenlevel = 0i32;
        let mut start = self.pos;

        // loop on all code_chuncks until we find a relevant open/close pattern
        loop {

            // do we need the next chunk?
            if self.end == self.pos {
                // get the next chunk of code
                match self.it.next() {
                    Some((ch_start, ch_end)) => {
                        self.end = ch_end;
                        if start == self.pos { start = ch_start; }
                        self.pos = ch_start;
                    }
                    None => {
                        // no more chunks. finished
                        return if start < self.end { Some((start, self.end)) }
                        else { None }
                    }
                }
            }

            if start == self.pos {
                // if this is a new stmt block, skip the whitespace
                for &b in src_bytes[self.pos..self.end].iter() {
                    match b {
                        b' ' | b'\r' | b'\n' | b'\t' => { self.pos += 1; },
                        _ => { break; }
                    }
                }
                start = self.pos;

                // test attribute   #[foo = bar]
                if self.pos<self.end && src_bytes[self.pos] == b'#' {
                    enddelim = b']'
                };
            }

            // iterate through the chunk, looking for stmt end
            for &b in src_bytes[self.pos..self.end].iter() {

                self.pos += 1;

                match b {
                    b'(' => { parenlevel += 1; },
                    b')' => { parenlevel -= 1; },
                    b'{' => {
                        // if we are top level and stmt is not a 'use' then
                        // closebrace finishes the stmt
                        if bracelevel == 0 && parenlevel == 0
                            && !(is_a_use_stmt(self.src, start, self.pos)) {
                            enddelim = b'}';
                        }
                        bracelevel += 1;
                    },
                    b'}' => {
                        // have we reached the end of the scope?
                        if bracelevel == 0 { return None; }
                        bracelevel -= 1;
                    },
                    b'!' => {
                        // macro if followed by at least one space or (
                        // FIXME: test with boolean 'not' expression
                        if parenlevel == 0 && bracelevel == 0
                            && self.pos < self.end && (self.pos-start)>1 {
                            match src_bytes[self.pos] {
                                b' ' | b'\r' | b'\n' | b'\t' | b'('  => {
                                    enddelim = b')';
                                },
                                _ => {}
                            }
                        }
                    }
                    _ => {}
                }

                if enddelim == b && bracelevel == 0 && parenlevel == 0 {
                    return Some((start, self.pos));
                }
            }
        }
    }
}

fn is_a_use_stmt(src: &str, start: usize, pos: usize) -> bool {
    let src_bytes = src.as_bytes();
    let whitespace = " {\t\r\n".as_bytes();
    (pos > 3 && &src_bytes[start..start+3] == b"use" &&
     whitespace.contains(&src_bytes[start+3])) ||
    (pos > 7 && &src_bytes[start..(start+7)] == b"pub use" &&
     whitespace.contains(&src_bytes[start+7]))
}

pub fn iter_stmts<'a>(src: &'a str) -> StmtIndicesIter<'a> {
    StmtIndicesIter{src: src, it: code_chunks(src), pos: 0, end: 0}
}

#[test]
fn iterates_single_use_stmts() {
    let src = &rejustify("
    use std::Foo; // a comment
    use std::Bar;
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("use std::Foo;", slice(src, it.next().unwrap()));
    assert_eq!("use std::Bar;", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_use_stmt_over_two_lines() {
    let src = &rejustify("
    use std::{Foo,
              Bar}; // a comment
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("use std::{Foo,
          Bar};", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_use_stmt_without_the_prefix() {
    let src = &rejustify("
    pub use {Foo,
              Bar}; // this is also legit apparently
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("pub use {Foo,
          Bar};", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_while_stmt() {
    let src = &rejustify("
    while self.pos < 3 { }
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("while self.pos < 3 { }", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_lambda_arg() {
    let src = &rejustify("
    myfn(|n|{});
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("myfn(|n|{});", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_macro() {
    let src = "
    mod foo;
    macro_rules! otry(
        ($e:expr) => (match $e { Some(e) => e, None => return })
    )
    mod bar;
    ";
    let mut it = iter_stmts(src);
    assert_eq!("mod foo;", slice(src, it.next().unwrap()));
    assert_eq!("macro_rules! otry(
        ($e:expr) => (match $e { Some(e) => e, None => return })
    )", slice(src, it.next().unwrap()));
    assert_eq!("mod bar;", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_macro_invocation() {
    let src = "
    mod foo;
    local_data_key!(local_stdout: Box<Writer + Send>)  // no ';'
    mod bar;
    ";
    let mut it = iter_stmts(src);
    assert_eq!("mod foo;", slice(src, it.next().unwrap()));
    assert_eq!("local_data_key!(local_stdout: Box<Writer + Send>)", slice(src, it.next().unwrap()));
    assert_eq!("mod bar;", slice(src, it.next().unwrap()));
}

// #[test]
// fn iterates_if_else_stmt() {
//     let src = rejustify("
//     if self.pos < 3 { } else { }
//     ");
//     let mut it = iter_stmts(src.as_slice());
//     assert_eq!("if self.pos < 3 { } else { }", slice(src.as_slice(), it.next().unwrap()));
// }

#[test]
fn iterates_inner_scope() {
    let src = "
    while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    }
    {
       b = foo;       // but not this
    }
    ";

    let scope = &src[25..];
    let mut it = iter_stmts(scope);

    assert_eq!("let a = 35;", slice(scope, it.next().unwrap()));
    assert_eq!("return a + 35;", slice(scope, it.next().unwrap()));
    assert_eq!(None, it.next());
}

#[test]
fn iterates_module_attribute() {
    let src = &rejustify("
    #![license = \"BSD\"]
    #[test]
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("#![license = \"BSD\"]", slice(src, it.next().unwrap()));
    assert_eq!("#[test]", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_half_open_subscope_if_is_the_last_thing() {
    let src = "
    let something = 35;
    while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    ";

    let scope = src;
    let mut it = iter_stmts(scope);
    assert_eq!("let something = 35;", slice(scope, it.next().unwrap()));
    assert_eq!("while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    ", slice(scope, it.next().unwrap()));
}

// fn main() {
//     use std::io::BufferedReader;
//     use std::io::File;
//     use std::str;

//     let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libstd/io/stdio.rs"))).read_to_end().unwrap();
//     let src = str::from_utf8(filetxt.as_slice()).unwrap();

//     for (start,end) in iter_stmts(src) {
//         println!("BLOB |{}|",src.slice(start,end));
//     }

// }
<commit_msg>Fix typo error<commit_after>// #![feature(phase)]
// #[phase(plugin, link)] extern crate log;

use racer::codecleaner::{code_chunks,CodeIndicesIter};
// use codecleaner::{code_chunks,CodeIndicesIter};
// mod codecleaner;

#[cfg(test)] use racer::testutils::{rejustify, slice};

pub struct StmtIndicesIter<'a> {
    src: &'a str,
    it: CodeIndicesIter<'a>,
    pos: usize,
    end: usize
}

impl<'a> Iterator for StmtIndicesIter<'a> {
    type Item = (usize, usize);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize)> {

        let src_bytes = self.src.as_bytes();
        let mut enddelim = b';';
        let mut bracelevel = 0u16;
        let mut parenlevel = 0i32;
        let mut start = self.pos;

        // loop on all code_chuncks until we find a relevant open/close pattern
        loop {

            // do we need the next chunk?
            if self.end == self.pos {
                // get the next chunk of code
                match self.it.next() {
                    Some((ch_start, ch_end)) => {
                        self.end = ch_end;
                        if start == self.pos { start = ch_start; }
                        self.pos = ch_start;
                    }
                    None => {
                        // no more chunks. finished
                        return if start < self.end { Some((start, self.end)) }
                        else { None }
                    }
                }
            }

            if start == self.pos {
                // if this is a new stmt block, skip the whitespace
                for &b in src_bytes[self.pos..self.end].iter() {
                    match b {
                        b' ' | b'\r' | b'\n' | b'\t' => { self.pos += 1; },
                        _ => { break; }
                    }
                }
                start = self.pos;

                // test attribute   #[foo = bar]
                if self.pos<self.end && src_bytes[self.pos] == b'#' {
                    enddelim = b']'
                };
            }

            // iterate through the chunk, looking for stmt end
            for &b in src_bytes[self.pos..self.end].iter() {

                self.pos += 1;

                match b {
                    b'(' => { parenlevel += 1; },
                    b')' => { parenlevel -= 1; },
                    b'{' => {
                        // if we are top level and stmt is not a 'use' then
                        // closebrace finishes the stmt
                        if bracelevel == 0 && parenlevel == 0
                            && !(is_a_use_stmt(self.src, start, self.pos)) {
                            enddelim = b'}';
                        }
                        bracelevel += 1;
                    },
                    b'}' => {
                        // have we reached the end of the scope?
                        if bracelevel == 0 { return None; }
                        bracelevel -= 1;
                    },
                    b'!' => {
                        // macro if followed by at least one space or (
                        // FIXME: test with boolean 'not' expression
                        if parenlevel == 0 && bracelevel == 0
                            && self.pos < self.end && (self.pos-start)>1 {
                            match src_bytes[self.pos] {
                                b' ' | b'\r' | b'\n' | b'\t' | b'('  => {
                                    enddelim = b')';
                                },
                                _ => {}
                            }
                        }
                    }
                    _ => {}
                }

                if enddelim == b && bracelevel == 0 && parenlevel == 0 {
                    return Some((start, self.pos));
                }
            }
        }
    }
}

fn is_a_use_stmt(src: &str, start: usize, pos: usize) -> bool {
    let src_bytes = src.as_bytes();
    let whitespace = " {\t\r\n".as_bytes();
    (pos > 3 && &src_bytes[start..start+3] == b"use" &&
     whitespace.contains(&src_bytes[start+3])) ||
    (pos > 7 && &src_bytes[start..(start+7)] == b"pub use" &&
     whitespace.contains(&src_bytes[start+7]))
}

pub fn iter_stmts<'a>(src: &'a str) -> StmtIndicesIter<'a> {
    StmtIndicesIter{src: src, it: code_chunks(src), pos: 0, end: 0}
}

#[test]
fn iterates_single_use_stmts() {
    let src = &rejustify("
    use std::Foo; // a comment
    use std::Bar;
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("use std::Foo;", slice(src, it.next().unwrap()));
    assert_eq!("use std::Bar;", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_use_stmt_over_two_lines() {
    let src = &rejustify("
    use std::{Foo,
              Bar}; // a comment
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("use std::{Foo,
          Bar};", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_use_stmt_without_the_prefix() {
    let src = &rejustify("
    pub use {Foo,
              Bar}; // this is also legit apparently
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("pub use {Foo,
          Bar};", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_while_stmt() {
    let src = &rejustify("
    while self.pos < 3 { }
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("while self.pos < 3 { }", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_lambda_arg() {
    let src = &rejustify("
    myfn(|n|{});
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("myfn(|n|{});", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_macro() {
    let src = "
    mod foo;
    macro_rules! otry(
        ($e:expr) => (match $e { Some(e) => e, None => return })
    )
    mod bar;
    ";
    let mut it = iter_stmts(src);
    assert_eq!("mod foo;", slice(src, it.next().unwrap()));
    assert_eq!("macro_rules! otry(
        ($e:expr) => (match $e { Some(e) => e, None => return })
    )", slice(src, it.next().unwrap()));
    assert_eq!("mod bar;", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_macro_invocation() {
    let src = "
    mod foo;
    local_data_key!(local_stdout: Box<Writer + Send>)  // no ';'
    mod bar;
    ";
    let mut it = iter_stmts(src);
    assert_eq!("mod foo;", slice(src, it.next().unwrap()));
    assert_eq!("local_data_key!(local_stdout: Box<Writer + Send>)", slice(src, it.next().unwrap()));
    assert_eq!("mod bar;", slice(src, it.next().unwrap()));
}

// #[test]
// fn iterates_if_else_stmt() {
//     let src = rejustify("
//     if self.pos < 3 { } else { }
//     ");
//     let mut it = iter_stmts(src.as_slice());
//     assert_eq!("if self.pos < 3 { } else { }", slice(src.as_slice(), it.next().unwrap()));
// }

#[test]
fn iterates_inner_scope() {
    let src = "
    while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    }
    {
       b = foo;       // but not this
    }
    ";

    let scope = &src[25..];
    let mut it = iter_stmts(scope);

    assert_eq!("let a = 35;", slice(scope, it.next().unwrap()));
    assert_eq!("return a + 35;", slice(scope, it.next().unwrap()));
    assert_eq!(None, it.next());
}

#[test]
fn iterates_module_attribute() {
    let src = &rejustify("
    #![license = \"BSD\"]
    #[test]
    ")[];
    let mut it = iter_stmts(src);
    assert_eq!("#![license = \"BSD\"]", slice(src, it.next().unwrap()));
    assert_eq!("#[test]", slice(src, it.next().unwrap()));
}

#[test]
fn iterates_half_open_subscope_if_is_the_last_thing() {
    let src = "
    let something = 35;
    while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    ";

    let scope = src;
    let mut it = iter_stmts(scope);
    assert_eq!("let something = 35;", slice(scope, it.next().unwrap()));
    assert_eq!("while self.pos < 3 {
       let a = 35;
       return a + 35;  // should iterate this
    ", slice(scope, it.next().unwrap()));
}

// fn main() {
//     use std::io::BufferedReader;
//     use std::io::File;
//     use std::str;

//     let filetxt = BufferedReader::new(File::open(&Path::new("/usr/local/src/rust/src/libstd/io/stdio.rs"))).read_to_end().unwrap();
//     let src = str::from_utf8(filetxt.as_slice()).unwrap();

//     for (start,end) in iter_stmts(src) {
//         println!("BLOB |{}|",src.slice(start,end));
//     }

// }
<|endoftext|>


<commit_before>//
//  Crontibuidores
//   - Dromedario de Chapéu
//

use rand::prelude::*;

fn verifica_ordem(lista: Vec<u8>) -> bool {
    for indice in 0..lista.len() - 1 {
        if lista[indice] > lista[indice + 1] {
            return false;
        }
    }
    return true;
}

// Vec<u8> significa que o parâmetro "lista" é uma lista de
// inteiros sem sinal de 8 bits. E o retorno u64 se refere
// ao total de ciclos necessários para realizar a ordenação
fn bogo_sort(mut lista: Vec<u8>) -> (Vec<u8>, u64) {
    let mut rng = thread_rng();
    // Foi escolhido um limite tão grande justamente pelo bogo sort
    // poder ser tanto o algoritmo mais rápido quanto o mais lento,
    // então para não crashar o programa é bom um range grande
    let mut ciclos: u64 = 0;
    loop {
        ciclos +=1;
        lista.shuffle(&mut rng);
        if verifica_ordem(lista.clone()) {
            return (lista, ciclos);
        }
    }
}

// O valor de u8 para os itens da lista é apenas para
// gerar números muito grandes e dificultar na visualização
fn gera_lista(len: u8) -> Vec<u8> {
    let mut rng = thread_rng();
    let mut lista = Vec::<u8>::new();
    for _ in 0..len - 1 {
        lista.push(rng.gen());
    }
    return lista;
}

fn main() {
    let lista_desordenada = gera_lista(6);
    print!("Lista desordenada: ");
    for i in lista_desordenada.iter() {
        print!("{i} ")
    }
    println!();

    let (lista, ciclos) = bogo_sort(lista_desordenada);
    println!("Foram necesarios um total de {ciclos} para ordenar");
    print!("Lista ordenada: ");
    for i in lista.iter() {
        print!("{i} ");
    }
    println!();
}

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

    #[test]
    fn oredenacao() {
        let mut desordenada = gera_lista(6);
        let (ordenada, _) = bogo_sort(desordenada.clone());
        desordenada.sort();
        assert_eq!(ordenada, desordenada);

        let desordenada = vec![6, 5, 4, 3, 2, 1];
        let (ordenada, _) = bogo_sort(desordenada);
        assert_eq!(ordenada, vec![1, 2, 3, 4, 5, 6]);
    }
}<commit_msg>Arrumando comentarios em bogo_sort.rs<commit_after>/*
    Contribuidores
        - Dromedario de Chapéu

    O Bogo Sort é um algoritmo feito apenas como uma piada, feito
    o pior e mais demorado algoritmo de ordenação. Tudo que ele faz
    é pegar uma lista, randomizar os seus itens, e verificar se todos
    os itens estão ordenados. Logo se tor 100% aleatório, o que pode
    fazer com que demore mais de 1 milhão de tentativas ate ser ordenado,
    ou que simplesmente na primeira tentativa ele seja ordenado.

*/

// Para utilizar esta lib sera necessário iniciar um projeto com o cargo
// e adicionar Rand as dependências
use rand::prelude::*;

fn verifica_ordem(lista: Vec<u8>) -> bool {
    for indice in 0..lista.len() - 1 {
        if lista[indice] > lista[indice + 1] {
            return false;
        }
    }
    return true;
}

// Vec<u8> significa que o parâmetro "lista" é uma lista de
// inteiros sem sinal de 8 bits. E o retorno u64 se refere
// ao total de ciclos necessários para realizar a ordenação
fn bogo_sort(mut lista: Vec<u8>) -> (Vec<u8>, u64) {
    let mut rng = thread_rng();
    // Foi escolhido um limite tão grande justamente pelo bogo sort
    // poder ser tanto o algoritmo mais rápido quanto o mais lento,
    // então para não crashar o programa é bom um range grande
    let mut ciclos: u64 = 0;
    loop {
        ciclos +=1;
        lista.shuffle(&mut rng);
        if verifica_ordem(lista.clone()) {
            return (lista, ciclos);
        }
    }
}

// O valor de u8 para os itens da lista é apenas para
// gerar números muito grandes e dificultar na visualização
fn gera_lista(len: u8) -> Vec<u8> {
    let mut rng = thread_rng();
    let mut lista = Vec::<u8>::new();
    for _ in 0..len - 1 {
        lista.push(rng.gen());
    }
    return lista;
}

fn main() {
    let lista_desordenada = gera_lista(6);
    print!("Lista desordenada: ");
    for i in lista_desordenada.iter() {
        print!("{i} ")
    }
    println!();

    let (lista, ciclos) = bogo_sort(lista_desordenada);
    println!("Foram necesarios um total de {ciclos} para ordenar");
    print!("Lista ordenada: ");
    for i in lista.iter() {
        print!("{i} ");
    }
    println!();
}

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

    #[test]
    fn oredenacao() {
        let mut desordenada = gera_lista(6);
        let (ordenada, _) = bogo_sort(desordenada.clone());
        desordenada.sort();
        assert_eq!(ordenada, desordenada);

        let desordenada = vec![6, 5, 4, 3, 2, 1];
        let (ordenada, _) = bogo_sort(desordenada);
        assert_eq!(ordenada, vec![1, 2, 3, 4, 5, 6]);
    }
}<|endoftext|>