<commit_before>extern crate libc;
extern crate openal;
extern crate cocoa;
extern crate time;
extern crate rustc_serialize;
extern crate objc;
extern crate std;

use std::collections::{VecDeque, BTreeMap};
use std::option::Option;
use std::io::Read;
use std::string::String;

use libc::{c_void};
use core_graphics::*;
use openal::al::*;
use openal::al::ffi::*;
use alut::*;
use objc::*;

use event_tap;

#[derive(RustcDecodable, RustcEncodable, Clone)]
pub struct AudioScheme
{
	pub name:String,
	pub display_name: String,
	pub files: Vec<String>,
	pub non_unique_count: u8,
	pub key_audio_map: BTreeMap<u8, u8>
}

pub struct Tickeys
{
	volume:f32,
	pitch:f32,

	audio_player: SimpleAudioPlayer,
	keymap: BTreeMap<u8, u8>,
	first_n_non_unique: i16,

	last_keys: VecDeque<u8>,

	keyboard_monitor: Option< event_tap::KeyboardMonitor>, //defered

	on_keydown: Option<fn(sender:&Tickeys, key: u8)>,

	schemes: Vec<AudioScheme>,
}

impl Tickeys
{
	pub fn new(schemes: Vec<AudioScheme>) -> Tickeys
	{
		unsafe
		{
			alutInit(std::ptr::null_mut(), std::ptr::null_mut());
		}

		Tickeys{
			volume:1f32,
			pitch:1f32,
			audio_player: SimpleAudioPlayer::new(2),
			keymap: BTreeMap::new(),
			first_n_non_unique: -1,
			last_keys: VecDeque::with_capacity(8),
			keyboard_monitor:None,
			on_keydown: Option::None,
			schemes: schemes,
		}
	}

	pub fn start(&mut self)
	{
		let tap;

		let ptr_to_self: *mut c_void = unsafe{std::mem::transmute(self)};

		unsafe
		{
			let tap_result = event_tap::KeyboardMonitor::new(Tickeys::handle_keyboard_event, ptr_to_self);

			match tap_result
			{
				Ok(t) => tap = t,
				Err(msg) => panic!("error: KeyboardMonitor::new: {}", msg)
			}

			let self_:&mut Tickeys = std::mem::transmute(ptr_to_self);
			self_.keyboard_monitor = Some(tap);
		}
	}

	pub fn stop(&mut self)
	{
		//todo: stop the kbd monitor?
	}

	pub fn get_schemes(&self) -> &Vec<AudioScheme>
	{
		&self.schemes
	}

	fn find_scheme(&self, name: &str) -> AudioScheme
	{
		self.schemes.iter().filter(|s|{ *(s.name) == *name}).next().unwrap().clone()
	}

	pub fn load_scheme(&mut self, dir: &str, scheme_name: &str)
	{
		let scheme = self.find_scheme(scheme_name);

		let mut audio_data = Vec::with_capacity(scheme.files.len());

		let mut path = dir.to_string() + "/";
		let base_path_len = path.chars().count();

		for f in scheme.files.iter()
		{
			path.push_str(f);
			println!("loading audio:{}", path);
			let audio = AudioData::from_file(&path);

			if audio.buffer == 0 as ALuint
			{
				panic!("failed to load audio file:{}", f);
			}

			path.truncate(base_path_len);

			audio_data.push(audio);
		}

		self.audio_player.load_data(audio_data);

		self.audio_player.set_gain(self.volume);
		self.audio_player.set_pitch(self.pitch);

		self.keymap = scheme.key_audio_map.clone();
		self.first_n_non_unique = scheme.non_unique_count as i16;
	}

	pub fn set_volume(&mut self, volume: f32)
	{
		if volume == self.volume {return;}
		self.volume = volume;

		self.audio_player.set_gain(volume);
	}

	pub fn set_pitch(&mut self, pitch: f32)
	{
		if pitch == self.pitch {return;}
		self.pitch = pitch;

		self.audio_player.set_pitch(pitch);
	}

	#[allow(dead_code)]
	pub fn get_volume(&self) -> f32
	{
		self.volume
	}

	#[allow(dead_code)]
	pub fn get_pitch(&self) -> f32
	{
		self.pitch
	}

	pub fn get_last_keys(&self) -> &VecDeque<u8>
	{
		&self.last_keys
	}

	#[allow(unused_variables)]
	extern fn handle_keyboard_event(proxy: CGEventTapProxy, etype: CGEventType, event: CGEventRef, refcon: *mut c_void) -> CGEventRef
	{
		let keycode = unsafe{CGEventGetIntegerValueField(event, CGEventField::kCGKeyboardEventKeycode)} as u16;

		assert!(refcon != 0 as *mut c_void);

		let tickeys: &mut Tickeys = unsafe{ std::mem::transmute(refcon)};
		tickeys.handle_keydown(keycode as u8);

		event
	}

	fn handle_keydown(&mut self, keycode: u8)
	{
		self.last_keys.push_back(keycode);
		if self.last_keys.len() > 6  //todo: make the length configurable
		{
			self.last_keys.pop_front();
		}

		match self.on_keydown
		{
			None => {},
			Some(f) => f(self, keycode)
		}

		//println!("key:{}", keycode);

		let index:i32 = match self.keymap.get(&keycode)
		{
			Some(idx) => *idx as i32,
			None =>
			{
				if self.first_n_non_unique <= 0
				{
					-1
				}else
				{
					(keycode % (self.first_n_non_unique as u8)) as i32
				}
			}
		};

		if self.is_too_frequent(keycode)
		{
			return;
		}

		if index == -1
		{
			return;
		}

		self.audio_player.play(index as usize);
	}

	pub fn set_on_keydown(&mut self, on_keydown: Option<fn(sender:&Tickeys, key: u8)>)
	{
		self.on_keydown = on_keydown;
	}

	fn is_too_frequent(&self, keycode: u8) -> bool
	{
		unsafe
		{
			static mut last_time: u64 = 0;
			static mut last_key: i16 = -1;
			let now = time::precise_time_ns() / 1000 / 1000;

			let delta = now - last_time ;

			if delta < 120 && last_key == (keycode as i16)
			{
				last_time = now;
				return true;
			}
			last_key = keycode as i16;
			last_time = now;

			return false;
		}

	}

}

pub struct AudioData
{
	buffer: ALuint,
}

impl AudioData
{
	//todo: how to handle error?
	pub fn from_file(file: &str) -> AudioData
	{
		let file_ptr = std::ffi::CString::new(file).unwrap().as_ptr();
		let mut audio = AudioData{buffer:0};

		unsafe
		{
			audio.buffer = alutCreateBufferFromFile(file_ptr);
			// Create sound source (use buffer to fill source)
    		//alGenSources(1, &mut audio.source);
    		//alSourcei(audio.source, AL_BUFFER, audio.buffer as ALint);

    		if audio.buffer == 0
    		{
    			panic!("failed to load file [{}]: {}", alutGetError() ,file);
    		}
		}

		audio
	}

	pub fn id(&self) -> ALuint
	{
		self.buffer
	}

}

impl Drop for AudioData
{
	fn drop(&mut self)
	{
		unsafe
		{
    		alDeleteBuffers(1, &self.buffer);
		}

	}
}

struct AudioSource
{
	id: ALuint,
}

impl AudioSource
{
	pub fn new() -> Option<AudioSource>
	{
		let mut id = 0;
		unsafe{ alGenSources(1, &mut id); }

		match unsafe { alGetError() }
		{
			AL_NO_ERROR => Some(AudioSource{id: id}),
			_ => None
		}
	}

	pub fn connect_to_buffer(&mut self, data: &AudioData)
	{
		self.stop();
		unsafe
		{
			alSourcei(self.id, AL_BUFFER, data.id() as ALint);

		}
	}

	pub fn disconnect_from_buffer(&mut self)
	{
		unsafe
		{
			alSourceStop(self.id);
			alSourcei(self.id, AL_BUFFER, 0);
		}
	}

	pub fn set_gain(&mut self, gain: f32)
	{
		unsafe{ alSourcef(self.id, AL_GAIN, gain); }
	}

	pub fn set_pitch(&mut self, pitch: f32)
	{
		unsafe{alSourcef(self.id, AL_PITCH, pitch);}
	}

	pub fn play(&mut self)
	{
		unsafe{ alSourcePlay(self.id); }
	}

	pub fn stop(&mut self)
	{
		unsafe{ alSourceStop(self.id); }
	}

	//pub fn state()
}

impl Drop for AudioSource
{
	fn drop(&mut self)
	{
		self.stop();
		unsafe{ alDeleteSources(1, &self.id); }
	}
}

struct SimpleAudioPlayer
{
	data: Vec<AudioData>,
	source_cache: VecDeque<AudioSource>,
	max_source_count: usize,
}

impl SimpleAudioPlayer
{
	pub fn new(max_source_count: usize) -> SimpleAudioPlayer
	{
		assert!(max_source_count > 0);

		let mut sources = VecDeque::with_capacity(max_source_count);
		for _ in 0..max_source_count
		{
			sources.push_back(AudioSource::new().unwrap());
		}

		SimpleAudioPlayer{data: Vec::new(), source_cache: sources, max_source_count: max_source_count}
	}

	pub fn load_data(&mut self, data: Vec<AudioData>)
	{
		for s in self.source_cache.iter_mut()
		{
			s.disconnect_from_buffer();
		}

		self.data = data;
	}

	pub fn set_gain(&mut self, gain: f32)
	{
		for s in self.source_cache.iter_mut()
		{
			s.set_gain(gain);
		}
	}

	pub fn set_pitch(&mut self, pitch: f32)
	{
		for s in self.source_cache.iter_mut()
		{
			s.set_pitch(pitch);
		}
	}

	pub fn play(&mut self, index: usize)
	{
		let data = match self.data.get(index)
		{
			Some(val) => val,
			None => return
		};

		let mut oldest_source = self.source_cache.pop_front().unwrap();

		oldest_source.connect_to_buffer(&data);
		oldest_source.play();

		self.source_cache.push_back(oldest_source);

	}

	pub fn unload_data(&mut self)
	{
		self.source_cache.clear();
		self.data.clear();
	}
}

impl Drop for SimpleAudioPlayer
{
	fn drop(&mut self)
	{
		self.unload_data();
	}
}

<commit_msg>clanups<commit_after>extern crate libc;
extern crate openal;
extern crate cocoa;
extern crate time;
extern crate rustc_serialize;
extern crate objc;
extern crate std;

use std::collections::{VecDeque, BTreeMap};
use std::option::Option;
use std::io::Read;
use std::string::String;

use libc::{c_void};
use core_graphics::*;
use openal::al::*;
use openal::al::ffi::*;
use alut::*;
use objc::*;

use event_tap;

#[derive(RustcDecodable, RustcEncodable, Clone)]
pub struct AudioScheme
{
	pub name:String,
	pub display_name: String,
	pub files: Vec<String>,
	pub non_unique_count: u8,
	pub key_audio_map: BTreeMap<u8, u8>
}

pub struct Tickeys
{
	volume:f32,
	pitch:f32,

	audio_player: SimpleAudioPlayer,
	keymap: BTreeMap<u8, u8>,
	first_n_non_unique: i16,

	last_keys: VecDeque<u8>,

	keyboard_monitor: Option< event_tap::KeyboardMonitor>, //defered

	on_keydown: Option<fn(sender:&Tickeys, key: u8)>,

	schemes: Vec<AudioScheme>,
}

impl Tickeys
{
	pub fn new(schemes: Vec<AudioScheme>) -> Tickeys
	{
		unsafe{alutInit(std::ptr::null_mut(), std::ptr::null_mut());}

		Tickeys
		{
			volume:1f32,
			pitch:1f32,
			audio_player: SimpleAudioPlayer::new(2),
			keymap: BTreeMap::new(),
			first_n_non_unique: -1,
			last_keys: VecDeque::with_capacity(8),
			keyboard_monitor:None,
			on_keydown: Option::None,
			schemes: schemes,
		}
	}

	pub fn start(&mut self)
	{
		let tap;
		let ptr_to_self: *mut c_void = unsafe{std::mem::transmute(self)};

		unsafe
		{
			let tap_result = event_tap::KeyboardMonitor::new(Tickeys::handle_keyboard_event, ptr_to_self);

			match tap_result
			{
				Ok(t) => tap = t,
				Err(msg) => panic!("error: KeyboardMonitor::new: {}", msg)
			}

			let self_:&mut Tickeys = std::mem::transmute(ptr_to_self);
			self_.keyboard_monitor = Some(tap);
		}
	}

	pub fn stop(&mut self)
	{
		//todo: stop the kbd monitor?
	}

	pub fn get_schemes(&self) -> &Vec<AudioScheme>
	{
		&self.schemes
	}

	fn find_scheme(&self, name: &str) -> AudioScheme
	{
		self.schemes.iter().filter(|s|{ *(s.name) == *name}).next().unwrap().clone()
	}

	pub fn load_scheme(&mut self, dir: &str, scheme_name: &str)
	{
		let scheme = self.find_scheme(scheme_name);
		let mut audio_data = Vec::with_capacity(scheme.files.len());
		let mut path = dir.to_string() + "/";
		let base_path_len = path.chars().count();

		for f in scheme.files.iter()
		{
			path.push_str(f);
			println!("loading audio:{}", path);
			let audio = AudioData::from_file(&path);
			if audio.buffer == 0 as ALuint
			{
				panic!("failed to load audio file:{}", f);
			}
			path.truncate(base_path_len);
			audio_data.push(audio);
		}

		self.audio_player.load_data(audio_data);
		self.audio_player.set_gain(self.volume);
		self.audio_player.set_pitch(self.pitch);

		self.keymap = scheme.key_audio_map.clone();
		self.first_n_non_unique = scheme.non_unique_count as i16;
	}

	pub fn set_volume(&mut self, volume: f32)
	{
		if volume == self.volume {return;}
		self.volume = volume;
		self.audio_player.set_gain(volume);
	}

	pub fn set_pitch(&mut self, pitch: f32)
	{
		if pitch == self.pitch {return;}
		self.pitch = pitch;
		self.audio_player.set_pitch(pitch);
	}

	#[allow(dead_code)]
	pub fn get_volume(&self) -> f32
	{
		self.volume
	}

	#[allow(dead_code)]
	pub fn get_pitch(&self) -> f32
	{
		self.pitch
	}

	pub fn get_last_keys(&self) -> &VecDeque<u8>
	{
		&self.last_keys
	}

	#[allow(unused_variables)]
	extern fn handle_keyboard_event(proxy: CGEventTapProxy, etype: CGEventType, event: CGEventRef, refcon: *mut c_void) -> CGEventRef
	{
		let keycode = unsafe{CGEventGetIntegerValueField(event, CGEventField::kCGKeyboardEventKeycode)} as u16;
		assert!(refcon != 0 as *mut c_void);
		let tickeys: &mut Tickeys = unsafe{ std::mem::transmute(refcon)};
		tickeys.handle_keydown(keycode as u8);

		event
	}

	fn handle_keydown(&mut self, keycode: u8)
	{
		self.last_keys.push_back(keycode);
		if self.last_keys.len() > 6  //todo: make the length configurable
		{
			self.last_keys.pop_front();
		}

		self.on_keydown.map(|f| f(self, keycode));

		let index:i32 = match self.keymap.get(&keycode)
		{
			Some(idx) => *idx as i32,
			None =>
			{
				if self.first_n_non_unique <= 0 { -1 }
				else { (keycode % (self.first_n_non_unique as u8)) as i32 }
			}
		};
		if self.is_too_frequent(keycode){ return; }
		if index == -1 { return; }

		self.audio_player.play(index as usize);
	}

	pub fn set_on_keydown(&mut self, on_keydown: Option<fn(sender:&Tickeys, key: u8)>)
	{
		self.on_keydown = on_keydown;
	}

	fn is_too_frequent(&self, keycode: u8) -> bool
	{
		unsafe
		{
			static mut last_time: u64 = 0;
			static mut last_key: i16 = -1;
			let now = time::precise_time_ns() / 1000 / 1000;

			let delta = now - last_time ;

			if delta < 120 && last_key == (keycode as i16)
			{
				last_time = now;
				return true;
			}
			last_key = keycode as i16;
			last_time = now;

			return false;
		}
	}
}

pub struct AudioData
{
	buffer: ALuint,
}

impl AudioData
{
	//todo: how to handle error?
	pub fn from_file(file: &str) -> AudioData
	{
		let file_ptr = std::ffi::CString::new(file).unwrap().as_ptr();
		let mut audio = AudioData{buffer:0};
		unsafe
		{
			audio.buffer = alutCreateBufferFromFile(file_ptr);
    		if audio.buffer == 0
    		{
    			panic!("failed to load file [{}]: {}", alutGetError() ,file);
    		}
		}

		audio
	}

	pub fn id(&self) -> ALuint
	{
		self.buffer
	}
}

impl Drop for AudioData
{
	fn drop(&mut self)
	{
		unsafe
		{
    		alDeleteBuffers(1, &self.buffer);
		}
	}
}

struct AudioSource
{
	id: ALuint,
}

impl AudioSource
{
	pub fn new() -> Option<AudioSource>
	{
		let mut id = 0;
		unsafe{ alGenSources(1, &mut id); }

		match unsafe { alGetError() }
		{
			AL_NO_ERROR => Some(AudioSource{id: id}),
			_ => None
		}
	}

	pub fn connect_to_buffer(&mut self, data: &AudioData)
	{
		self.stop();
		unsafe
		{
			alSourcei(self.id, AL_BUFFER, data.id() as ALint);
		}
	}

	pub fn disconnect_from_buffer(&mut self)
	{
		unsafe
		{
			alSourceStop(self.id);
			alSourcei(self.id, AL_BUFFER, 0);
		}
	}

	pub fn set_gain(&mut self, gain: f32)
	{
		unsafe{ alSourcef(self.id, AL_GAIN, gain); }
	}

	pub fn set_pitch(&mut self, pitch: f32)
	{
		unsafe{alSourcef(self.id, AL_PITCH, pitch);}
	}

	pub fn play(&mut self)
	{
		unsafe{ alSourcePlay(self.id); }
	}

	pub fn stop(&mut self)
	{
		unsafe{ alSourceStop(self.id); }
	}

	//pub fn state()
}

impl Drop for AudioSource
{
	fn drop(&mut self)
	{
		self.stop();
		unsafe{ alDeleteSources(1, &self.id); }
	}
}

struct SimpleAudioPlayer
{
	data: Vec<AudioData>,
	source_cache: VecDeque<AudioSource>,
	max_source_count: usize,
}

impl SimpleAudioPlayer
{
	pub fn new(max_source_count: usize) -> SimpleAudioPlayer
	{
		assert!(max_source_count > 0);

		let mut sources = VecDeque::with_capacity(max_source_count);
		for _ in 0..max_source_count
		{
			sources.push_back(AudioSource::new().unwrap());
		}

		SimpleAudioPlayer{data: Vec::new(), source_cache: sources, max_source_count: max_source_count}
	}

	pub fn load_data(&mut self, data: Vec<AudioData>)
	{
		for s in self.source_cache.iter_mut()
		{
			s.disconnect_from_buffer();
		}

		self.data = data;
	}

	pub fn set_gain(&mut self, gain: f32)
	{
		for s in self.source_cache.iter_mut()
		{
			s.set_gain(gain);
		}
	}

	pub fn set_pitch(&mut self, pitch: f32)
	{
		for s in self.source_cache.iter_mut()
		{
			s.set_pitch(pitch);
		}
	}

	pub fn play(&mut self, index: usize)
	{
		let data = match self.data.get(index)
		{
			Some(val) => val,
			None => return
		};

		let mut oldest_source = self.source_cache.pop_front().unwrap();

		oldest_source.connect_to_buffer(&data);
		oldest_source.play();

		self.source_cache.push_back(oldest_source);
	}

	pub fn unload_data(&mut self)
	{
		self.source_cache.clear();
		self.data.clear();
	}
}

impl Drop for SimpleAudioPlayer
{
	fn drop(&mut self)
	{
		self.unload_data();
	}
}
<|endoftext|>


<commit_before>//! The collection keeps and maintains all audio data.
use super::{super::config, bktree::BKTree};

use id3::Tag;
use libp2p_core::PeerId;
use std::{
    fs::{self, DirEntry}, // directory
    io,                   // reading files
    path::Path,
    sync::{Arc as SArc, Mutex as SMutex},
};
use tree_magic;

static TOLERANCE: usize = 5;
static TIME_TOLERANCE_SEC: usize = 4;

struct AudioInfo {
    duration: u32,
    album: String,
}

// todo: think over this, peer and max threads ... kick it out
//       threads are interesting to fill in unused threads in path
//       for string distance with rayon!
#[allow(dead_code)]
struct Worker {
    /// identify them.
    peer_id: PeerId,
    max_threads: usize,
}

/// # Worker
/// the worker is supposed to be running on different machines
/// with one server and many clients
impl Worker {
    /// # Just new
    /// To identify how to comment
    /// # Arguments
    /// * 'id' - the identification (each will create an own hash)
    /// * 'max_threads' - how many threads can the worker create
    pub fn new(peer_id: PeerId, max_threads: usize) -> Worker {
        Worker {
            peer_id: peer_id,
            max_threads: max_threads,
        }
    }
}

pub struct Container {
    bk_tree: BKTree<String, Box<AudioInfo>>,
}
impl Container {
    pub fn new() -> Self {
        Self {
            bk_tree: BKTree::new(),
        }
    }
}

pub struct Collection {
    who: Worker,
    /// This collection contains all data
    stats: Stats,
}
/// Only some statistics
pub struct FilesStat {
    pub analyzed: u32,
    pub faulty: u32,
    pub searched: u32,
    pub other: u32,
}

impl FilesStat {
    /// Adds stats from one to the other,
    /// used for combining different thread
    /// results.
    fn add(&mut self, other: &FilesStat) {
        self.analyzed += other.analyzed;
        self.faulty += other.faulty;
        self.searched += other.searched;
        self.other += other.other;
    }
}

struct Stats {
    files: FilesStat,
    threads: usize,
}

type FileFn =
    dyn Fn(&mut Collection, SArc<SMutex<Container>>, &DirEntry, &mut FilesStat) -> io::Result<()>;

impl Collection {
    /// Sets up the whole collection that books all threads.
    pub fn new(peer_id: &PeerId, num_threads: usize) -> Collection {
        Collection {
            who: Worker::new(peer_id.clone(), num_threads),
            stats: Stats {
                files: FilesStat {
                    analyzed: 0,
                    faulty: 0,
                    searched: 0,
                    other: 0,
                },
                threads: num_threads,
            },
        }
    }

    /// The function that runs from a certain path
    pub fn visit_path(
        &mut self,
        container: SArc<SMutex<Container>>,
        dir: &Path,
        cb: &FileFn,
    ) -> io::Result<FilesStat> {
        let mut file_stats = FilesStat {
            analyzed: 0,
            faulty: 0,
            searched: 0,
            other: 0,
        };

        if dir.is_dir() {
            // todo: go with free threads in the search with rayon
            for entry in fs::read_dir(dir)? {
                let mut loop_file_stats = &mut file_stats;

                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    let file_stats_loop = self.visit_path(container.clone(), &path, cb)?;
                    loop_file_stats.add(&file_stats_loop);
                } else {
                    cb(self, container.clone(), &entry, &mut loop_file_stats).or_else(
                        |io_error| {
                            warn!("{:?}", io_error);
                            Err(io_error)
                        },
                    )?
                }
            }
        }
        Ok(file_stats)
    }

    /// the function to check all files separately
    pub fn visit_files(
        col: &mut Collection,
        data: SArc<SMutex<Container>>,
        cb: &DirEntry,
        file_stats: &mut FilesStat,
    ) -> io::Result<()> {
        // count stats
        col.stats.files.searched += 1;
        file_stats.searched += 1;

        let filetype = tree_magic::from_filepath(&cb.path());
        let prefix = filetype.split("/").nth(0);
        match prefix {
            Some("audio") => {
                if let Some(suffix) = filetype.split("/").last() {
                    if config::data::IGNORE_AUDIO_FORMATS
                        .iter()
                        .any(|&s| s == suffix)
                    {
                        col.stats.files.other += 1;
                        file_stats.other += 1;
                        Ok(())
                    } else {
                        col.visit_audio_files(data, &cb.path(), file_stats)
                            .or_else(|_| {
                                col.stats.files.faulty += 1;
                                file_stats.faulty += 1;
                                error!("ts: {:?}", filetype);
                                Err(io::Error::new(io::ErrorKind::Other, "unknown audio file!"))
                            })
                    }
                } else {
                    col.stats.files.faulty += 1;
                    file_stats.faulty += 1;
                    Ok(())
                }
            }
            // FIXME: video in taglib holds also oga which are audio indeed ...
            Some("text") | Some("application") | Some("image") | Some("video") => Ok(()),
            _ => {
                error!("[{:?}]{:?}", prefix, cb.path());
                col.stats.files.other += 1;
                file_stats.other += 1;
                Ok(())
            }
        }
    }

    /// Check the file and retrieve the meta-data info
    fn visit_audio_files(
        &mut self,
        data: SArc<SMutex<Container>>,
        cb: &Path,
        file_stats: &mut FilesStat,
    ) -> Result<(), ()> {
        Tag::read_from_path(cb.to_str().unwrap())
            .and_then(|tag| {
                let artist = tag.artist().unwrap_or("");
                let title = tag.title().unwrap_or("");
                let duration = tag.duration().unwrap_or(0);
                let album = tag.album().unwrap_or("");

                self.stats.files.analyzed += 1;
                file_stats.analyzed += 1;

                // artist + song name is key for bktree
                let key = [artist, title].join(" ");

                let ref mut locked_bktree = data.lock().unwrap().bk_tree;
                let (vec_k, vec_c) = locked_bktree.find(&key, TOLERANCE);
                if !vec_c.is_empty() {
                    let mut vec_similar = vec![];
                    for (index, similar) in vec_k.iter().enumerate() {
                        let time_distance = similar.duration as i32 - duration as i32;
                        if time_distance.abs() < TIME_TOLERANCE_SEC as i32 {
                            vec_similar.push(vec_c[index]);
                        }
                    }
                    if !vec_similar.is_empty() {
                        trace!(
                            "close: {:?} to {:?}, {} similar",
                            &vec_similar,
                            &key,
                            &vec_k.len()
                        );
                    }
                }

                // todo: decide when to not add and insert then
                locked_bktree.insert(
                    key.clone(),
                    Box::new(AudioInfo {
                        duration,
                        album: album.to_string(),
                    }),
                );
                Ok(())
            })
            .or_else(|_| {
                self.stats.files.faulty += 1;
                file_stats.faulty += 1;
                Ok(())
            })
    }

    pub fn print_stats(&self) {
        let output_string = format!(
            "This client's id     : {id:}\n\
             pathes/threads       : {nr_pathes:>width$}\n\
             ----------------------     \n\
             analyzed files       : {files_analyzed:>width$}\n\
             searched files       : {files_searched:>width$}\n\
             irrelevant files     : {files_irrelevant:>width$}\n\
             faulty files         : {files_faulty:>width$}\n",
            id = self.who.peer_id.to_string().to_uppercase(),
            nr_pathes = self.stats.threads,
            files_analyzed = self.stats.files.analyzed,
            files_searched = self.stats.files.searched,
            files_irrelevant = self.stats.files.other,
            files_faulty = self.stats.files.faulty, // awesome, really
            width = 5
        );

        info!("{}", output_string);
    }
}
<commit_msg>[collection] fix misunderstood find value return and the following behavior<commit_after>//! The collection keeps and maintains all audio data.
use super::{super::config, bktree::BKTree};

use id3::Tag;
use libp2p_core::PeerId;
use std::{
    fs::{self, DirEntry}, // directory
    io,                   // reading files
    path::Path,
    sync::{Arc as SArc, Mutex as SMutex},
};
use tree_magic;

static TOLERANCE: usize = 5;

struct AudioInfo {
    duration: u32,
    album: String,
}

// todo: think over this, peer and max threads ... kick it out
//       threads are interesting to fill in unused threads in path
//       for string distance with rayon!
#[allow(dead_code)]
struct Worker {
    /// identify them.
    peer_id: PeerId,
    max_threads: usize,
}

/// # Worker
/// the worker is supposed to be running on different machines
/// with one server and many clients
impl Worker {
    /// # Just new
    /// To identify how to comment
    /// # Arguments
    /// * 'id' - the identification (each will create an own hash)
    /// * 'max_threads' - how many threads can the worker create
    pub fn new(peer_id: PeerId, max_threads: usize) -> Worker {
        Worker {
            peer_id: peer_id,
            max_threads: max_threads,
        }
    }
}

pub struct Container {
    bk_tree: BKTree<String, Box<AudioInfo>>,
}
impl Container {
    pub fn new() -> Self {
        Self {
            bk_tree: BKTree::new(),
        }
    }
}

pub struct Collection {
    who: Worker,
    /// This collection contains all data
    stats: Stats,
}
/// Only some statistics
pub struct FilesStat {
    pub analyzed: u32,
    pub faulty: u32,
    pub searched: u32,
    pub other: u32,
}

impl FilesStat {
    /// Adds stats from one to the other,
    /// used for combining different thread
    /// results.
    fn add(&mut self, other: &FilesStat) {
        self.analyzed += other.analyzed;
        self.faulty += other.faulty;
        self.searched += other.searched;
        self.other += other.other;
    }
}

struct Stats {
    files: FilesStat,
    threads: usize,
}

type FileFn =
    dyn Fn(&mut Collection, SArc<SMutex<Container>>, &DirEntry, &mut FilesStat) -> io::Result<()>;

impl Collection {
    /// Sets up the whole collection that books all threads.
    pub fn new(peer_id: &PeerId, num_threads: usize) -> Collection {
        Collection {
            who: Worker::new(peer_id.clone(), num_threads),
            stats: Stats {
                files: FilesStat {
                    analyzed: 0,
                    faulty: 0,
                    searched: 0,
                    other: 0,
                },
                threads: num_threads,
            },
        }
    }

    /// The function that runs from a certain path
    pub fn visit_path(
        &mut self,
        container: SArc<SMutex<Container>>,
        dir: &Path,
        cb: &FileFn,
    ) -> io::Result<FilesStat> {
        let mut file_stats = FilesStat {
            analyzed: 0,
            faulty: 0,
            searched: 0,
            other: 0,
        };

        if dir.is_dir() {
            // todo: go with free threads in the search with rayon
            for entry in fs::read_dir(dir)? {
                let mut loop_file_stats = &mut file_stats;

                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    let file_stats_loop = self.visit_path(container.clone(), &path, cb)?;
                    loop_file_stats.add(&file_stats_loop);
                } else {
                    cb(self, container.clone(), &entry, &mut loop_file_stats).or_else(
                        |io_error| {
                            warn!("{:?}", io_error);
                            Err(io_error)
                        },
                    )?
                }
            }
        }
        Ok(file_stats)
    }

    /// the function to check all files separately
    pub fn visit_files(
        col: &mut Collection,
        data: SArc<SMutex<Container>>,
        cb: &DirEntry,
        file_stats: &mut FilesStat,
    ) -> io::Result<()> {
        // count stats
        col.stats.files.searched += 1;
        file_stats.searched += 1;

        let filetype = tree_magic::from_filepath(&cb.path());
        let prefix = filetype.split("/").nth(0);
        match prefix {
            Some("audio") => {
                if let Some(suffix) = filetype.split("/").last() {
                    if config::data::IGNORE_AUDIO_FORMATS
                        .iter()
                        .any(|&s| s == suffix)
                    {
                        col.stats.files.other += 1;
                        file_stats.other += 1;
                        Ok(())
                    } else {
                        col.visit_audio_files(data, &cb.path(), file_stats)
                            .or_else(|_| {
                                col.stats.files.faulty += 1;
                                file_stats.faulty += 1;
                                error!("ts: {:?}", filetype);
                                Err(io::Error::new(io::ErrorKind::Other, "unknown audio file!"))
                            })
                    }
                } else {
                    col.stats.files.faulty += 1;
                    file_stats.faulty += 1;
                    Ok(())
                }
            }
            // FIXME: video in taglib holds also oga which are audio indeed ...
            Some("text") | Some("application") | Some("image") | Some("video") => Ok(()),
            _ => {
                error!("[{:?}]{:?}", prefix, cb.path());
                col.stats.files.other += 1;
                file_stats.other += 1;
                Ok(())
            }
        }
    }

    /// Check the file and retrieve the meta-data info
    fn visit_audio_files(
        &mut self,
        data: SArc<SMutex<Container>>,
        cb: &Path,
        file_stats: &mut FilesStat,
    ) -> Result<(), ()> {
        Tag::read_from_path(cb.to_str().unwrap())
            .and_then(|tag| {
                let artist = tag.artist().unwrap_or("");
                let title = tag.title().unwrap_or("");
                let duration = tag.duration().unwrap_or(0);
                let album = tag.album().unwrap_or("");

                self.stats.files.analyzed += 1;
                file_stats.analyzed += 1;

                // artist + song name is key for bktree
                let key = [artist, title].join(" ");

                let ref mut locked_bktree = data.lock().unwrap().bk_tree;
                let (vec_exact_match, vec_similarities) = locked_bktree.find(&key, TOLERANCE);
                if !vec_similarities.is_empty() {
                    trace!("close: {:?} to {:?},", &vec_similarities, &key);
                }
                // if exact match, don't insert!!
                if vec_exact_match.is_empty() {
                    // todo: also decide when to not add and insert then
                    locked_bktree.insert(
                        key.clone(),
                        Box::new(AudioInfo {
                            duration,
                            album: album.to_string(),
                        }),
                    );
                } else {
                    // exact match with certain AudioInfo
                    trace!(
                        "for {:?}, {} exact matches found!",
                        &key,
                        vec_exact_match.len()
                    );
                    for audio_info in vec_exact_match {
                        let time_distance = audio_info.duration as i32 - duration as i32;
                        if time_distance.abs() > 0 {
                            trace!(
                                "same: but time differs {} seconds with album name old '{}' and new: '{}'!",
                                time_distance,
                                audio_info.album,
                                album
                            );
                        }
                    }
                }
                Ok(())
            })
            .or_else(|_| {
                self.stats.files.faulty += 1;
                file_stats.faulty += 1;
                Ok(())
            })
    }

    pub fn print_stats(&self) {
        let output_string = format!(
            "This client's id     : {id:}\n\
             pathes/threads       : {nr_pathes:>width$}\n\
             ----------------------     \n\
             analyzed files       : {files_analyzed:>width$}\n\
             searched files       : {files_searched:>width$}\n\
             irrelevant files     : {files_irrelevant:>width$}\n\
             faulty files         : {files_faulty:>width$}\n",
            id = self.who.peer_id.to_string().to_uppercase(),
            nr_pathes = self.stats.threads,
            files_analyzed = self.stats.files.analyzed,
            files_searched = self.stats.files.searched,
            files_irrelevant = self.stats.files.other,
            files_faulty = self.stats.files.faulty, // awesome, really
            width = 5
        );

        info!("{}", output_string);
    }
}
<|endoftext|>


<commit_before>use ignore::{self, gitignore};

use crate::config::{FileName, IgnoreList};

pub(crate) struct IgnorePathSet {
    ignore_set: gitignore::Gitignore,
}

impl IgnorePathSet {
    pub(crate) fn from_ignore_list(ignore_list: &IgnoreList) -> Result<Self, ignore::Error> {
        let mut ignore_builder = gitignore::GitignoreBuilder::new(ignore_list.rustfmt_toml_path());

        for ignore_path in ignore_list {
            ignore_builder.add_line(None, ignore_path.to_str().unwrap())?;
        }

        Ok(IgnorePathSet {
            ignore_set: ignore_builder.build()?,
        })
    }

    pub(crate) fn is_match(&self, file_name: &FileName) -> bool {
        match file_name {
            FileName::Stdin => false,
            FileName::Real(p) => self
                .ignore_set
                .matched_path_or_any_parents(p, false)
                .is_ignore(),
        }
    }
}

#[cfg(test)]
mod test {
    use std::path::{Path, PathBuf};

    use crate::config::{Config, FileName};
    use crate::ignore_path::IgnorePathSet;

    #[test]
    fn test_ignore_path_set() {
        match option_env!("CFG_RELEASE_CHANNEL") {
            // this test requires nightly
            None | Some("nightly") => {
                let config =
                    Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new(""))
                        .unwrap();
                let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();

                assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
                assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
                assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
            }
            _ => (),
        };
    }
}
<commit_msg>Update nightly only test with #[nightly_only_test] attribute<commit_after>use ignore::{self, gitignore};

use crate::config::{FileName, IgnoreList};

pub(crate) struct IgnorePathSet {
    ignore_set: gitignore::Gitignore,
}

impl IgnorePathSet {
    pub(crate) fn from_ignore_list(ignore_list: &IgnoreList) -> Result<Self, ignore::Error> {
        let mut ignore_builder = gitignore::GitignoreBuilder::new(ignore_list.rustfmt_toml_path());

        for ignore_path in ignore_list {
            ignore_builder.add_line(None, ignore_path.to_str().unwrap())?;
        }

        Ok(IgnorePathSet {
            ignore_set: ignore_builder.build()?,
        })
    }

    pub(crate) fn is_match(&self, file_name: &FileName) -> bool {
        match file_name {
            FileName::Stdin => false,
            FileName::Real(p) => self
                .ignore_set
                .matched_path_or_any_parents(p, false)
                .is_ignore(),
        }
    }
}

#[cfg(test)]
mod test {
    use std::path::{Path, PathBuf};

    use crate::config::{Config, FileName};
    use crate::ignore_path::IgnorePathSet;

    use rustfmt_config_proc_macro::nightly_only_test;

    #[nightly_only_test]
    #[test]
    fn test_ignore_path_set() {
        let config =
            Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new("")).unwrap();
        let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();

        assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
        assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
        assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
    }
}
<|endoftext|>


<commit_before>use header::*;
use instructions::Instruction as Instr;
use num::FromPrimitive;

#[derive(Debug, Default)]
pub struct Interpreter {
    // File data
    header: RaptorHeader,
    bytecode: Vec<u8>,

    // Runtime stuff
    stack: Vec<i32>,
    memory: Vec<i32>,
    program_counter: usize,
}

impl Interpreter {
    pub fn new(mut data: Vec<u8>) -> Interpreter {
        let mut i = Interpreter {
            header: read_header(&data),
            bytecode: data.drain(HEADER_SIZE..).collect(),
            stack: Vec::new(),
            memory: Vec::new(),
            program_counter: 0,
        };
        i.memory.resize(i.header.var_count as usize, 0);
        i
    }

    pub fn run(&mut self, options: &::Options) {
        use std::ops::*;
        use std::cmp::*;

        debug!("Running...");
        debug!("Bytecode: {:?}", self.bytecode);

        let debug = options.debug;

        // Main loop
        // Will break when .next() is None
        while self.program_counter != self.bytecode.len() {
            // info!("PC: {}", program_counter);

            // Use FromPrimitive trait to convert a value to its enum
            let instr = Instr::from_u8(self.bytecode[self.program_counter]);
            self.program_counter += 1;

            if instr.is_none() {
                warn!("Unimplemented instruction: {:04X}", self.bytecode[self.program_counter]);
                continue;
            }

            let instr = instr.unwrap();   // We're sure it's Some here, so unpack it.

            if options.debug {
                debug!("{:?}", instr);
            }

            macro_rules! push {
                ( $x:expr ) => {
                    (self.stack.push($x));
                };
            }
            macro_rules! pop {
                () => {
                    (self.stack.pop());
                };
            }
            macro_rules! operation {
                ($op:ident) => ({
                    let final_length: usize = self.stack.len().saturating_sub(2);
                    let val = self.stack.drain(final_length..).fold(
                        0, |acc, x| acc.$op(x)
                    );
                    push!(val);
                })
            }
            macro_rules! reljump {
                ($op:ident) => ({
                    let top = pop!().unwrap();
                    if top.$op(&0) {
                        reljump!();
                    } else {
                        self.get_next_4_bytes();
                        if debug {debug!("Jump not taken"); }
                    }
                });
                () => ({
                    let offset = (self.get_next_4_bytes() - 1) as i32;
                    // Need this if because you can't have negative usizes
                    if offset > 0 {
                        if debug {debug!("RELJUMP: {}", offset);}
                        self.program_counter += offset as usize;
                        if offset == 1 {debug!("RELJUMP 1 is redundant. This is a compiler bug")}
                    } else if offset < 0 {
                        if debug {debug!("RELJUMP: {}", offset);}
                        self.program_counter -= (-offset) as usize;
                    } else {
                        warn!("Invalid reljump offset: 0");
                    }
                });
            }
            // TODO: More macros, less code

            match instr {
                Instr::NOP => {},
                Instr::HALT => {
                    println!("HALT issued, stopped execution.");
                    if debug {
                        debug!("Stack: {:?}", self.stack);
                        debug!("Memory: {:?}", self.memory);
                    }
                },
                Instr::ICONST => {
                    let b = self.get_next_4_bytes() as i32;
                    push!(b);
                },
                Instr::POP => { pop!(); },
                Instr::ADD =>       { operation!(add);    },
                Instr::SUB =>       { operation!(sub);    },
                Instr::MULTIPLY =>  { operation!(mul);    },
                Instr::DIVIDE =>    { operation!(div);    },
                Instr::MODULUS =>   { operation!(rem);    },
                Instr::RSHIFT =>    { operation!(shl);    },
                Instr::LSHIFT =>    { operation!(shr);    },
                Instr::AND =>       { operation!(bitand); },
                Instr::OR =>        { operation!(bitor);  },
                Instr::NOT =>       {
                    let val = pop!().unwrap();
                    push!(val.not());
                },
                Instr::COMP => {
                    let a = pop!(); let b = pop!();
                    push!(if a > b {1} else if a < b {-1} else {0});
                },
                Instr::COMP_LT => {
                    let a = pop!(); let b = pop!();
                    push!(if a < b {1} else {0});
                },
                Instr::COMP_EQ => {
                    let a = pop!(); let b = pop!();
                    push!(if a == b {1} else {0});
                },
                Instr::COMP_GT => {
                    let a = pop!(); let b = pop!();
                    push!(if a > b {1} else {0});
                },
                Instr::RELJUMP => {reljump!();},
                Instr::RELJUMP_GT => {reljump!(gt);},
                Instr::RELJUMP_LT => {reljump!(lt);},
                Instr::RELJUMP_EQ => {reljump!(eq);},
                Instr::STORE => {
                    let index = self.get_next_4_bytes() as usize;
                    self.memory[index] = pop!().unwrap();
                },
                Instr::LOAD => {
                    let index = self.get_next_4_bytes() as usize;
                    push!(self.memory[index]);
                },
                Instr::PRINT => {
                    println!("PRINT: {}", pop!().unwrap());
                },
                Instr::DUMP_STACK => {
                    println!("{:?}", self.stack);
                },
                Instr::DUMP_GLOBALS => {
                    println!("{:?}", self.memory);},
            }
        }
    }

    fn get_next_4_bytes(&mut self) -> u32 {
        let val = (self.bytecode[self.program_counter] as u32) << 24 |
                  (self.bytecode[self.program_counter + 1] as u32) << 16 |
                  (self.bytecode[self.program_counter + 2] as u32) << 8 |
                  (self.bytecode[self.program_counter + 3] as u32);
        self.program_counter += 4;
        debug!("get_next_4_bytes: 0x{:04X}", val);
        val
    }
}

// TODO: Add tests
<commit_msg>Even more macros - even less code<commit_after>use header::*;
use instructions::Instruction as Instr;
use num::FromPrimitive;

#[derive(Debug, Default)]
pub struct Interpreter {
    // File data
    header: RaptorHeader,
    bytecode: Vec<u8>,

    // Runtime stuff
    stack: Vec<i32>,
    memory: Vec<i32>,
    program_counter: usize,
}

impl Interpreter {
    pub fn new(mut data: Vec<u8>) -> Interpreter {
        let mut i = Interpreter {
            header: read_header(&data),
            bytecode: data.drain(HEADER_SIZE..).collect(),
            stack: Vec::new(),
            memory: Vec::new(),
            program_counter: 0,
        };
        i.memory.resize(i.header.var_count as usize, 0);
        i
    }

    pub fn run(&mut self, options: &::Options) {
        use std::ops::*;
        use std::cmp::*;

        debug!("Running...");
        debug!("Bytecode: {:?}", self.bytecode);

        let debug = options.debug;

        // Main loop
        // Will break when .next() is None
        while self.program_counter != self.bytecode.len() {
            // info!("PC: {}", program_counter);

            // Use FromPrimitive trait to convert a value to its enum
            let instr = Instr::from_u8(self.bytecode[self.program_counter]);
            self.program_counter += 1;

            if instr.is_none() {
                warn!("Unimplemented instruction: {:04X}", self.bytecode[self.program_counter]);
                continue;
            }

            let instr = instr.unwrap();   // We're sure it's Some here, so unpack it.

            if options.debug {
                debug!("{:?}", instr);
            }

            macro_rules! push {
                ( $x:expr ) => {
                    (self.stack.push($x));
                };
            }
            macro_rules! pop {
                () => {
                    (self.stack.pop());
                };
            }
            macro_rules! operation {
                ($op:ident) => ({
                    let final_length: usize = self.stack.len().saturating_sub(2);
                    let val = self.stack.drain(final_length..).fold(
                        0, |acc, x| acc.$op(x)
                    );
                    push!(val);
                })
            }
            macro_rules! reljump {
                ($op:ident) => ({
                    let top = pop!().unwrap();
                    if top.$op(&0) {
                        reljump!();
                    } else {
                        self.get_next_4_bytes();
                        if debug {debug!("Jump not taken"); }
                    }
                });
                () => ({
                    let offset = (self.get_next_4_bytes() - 1) as i32;
                    // Need this if because you can't have negative usizes
                    if offset > 0 {
                        if debug {debug!("RELJUMP: {}", offset);}
                        self.program_counter += offset as usize;
                        if offset == 1 {debug!("RELJUMP 1 is redundant. This is a compiler bug")}
                    } else if offset < 0 {
                        if debug {debug!("RELJUMP: {}", offset);}
                        self.program_counter -= (-offset) as usize;
                    } else {
                        warn!("Invalid reljump offset: 0");
                    }
                });
            }
            // TODO: More macros, less code

            match instr {
                Instr::NOP => {},
                Instr::HALT => {
                    println!("HALT issued, stopped execution.");
                    if debug {
                        debug!("Stack: {:?}", self.stack);
                        debug!("Memory: {:?}", self.memory);
                    }
                },
                Instr::ICONST => {
                    let b = self.get_next_4_bytes() as i32;
                    push!(b);
                },
                Instr::POP => { pop!(); },
                Instr::ADD =>       { operation!(add);    },
                Instr::SUB =>       { operation!(sub);    },
                Instr::MULTIPLY =>  { operation!(mul);    },
                Instr::DIVIDE =>    { operation!(div);    },
                Instr::MODULUS =>   { operation!(rem);    },
                Instr::RSHIFT =>    { operation!(shl);    },
                Instr::LSHIFT =>    { operation!(shr);    },
                Instr::AND =>       { operation!(bitand); },
                Instr::OR =>        { operation!(bitor);  },
                Instr::NOT =>       {
                    let val = pop!().unwrap();
                    push!(val.not());
                },
                Instr::COMP => {
                    let a = pop!(); let b = pop!();
                    push!(if a > b {1} else if a < b {-1} else {0});
                },
                Instr::COMP_LT => {push!(if pop!() < pop!() {1} else {0});},
                Instr::COMP_EQ => {push!(if pop!() == pop!() {1} else {0});},
                Instr::COMP_GT => {push!(if pop!() > pop!() {1} else {0});},
                Instr::RELJUMP => {reljump!();},
                Instr::RELJUMP_GT => {reljump!(gt);},
                Instr::RELJUMP_LT => {reljump!(lt);},
                Instr::RELJUMP_EQ => {reljump!(eq);},
                Instr::STORE => {
                    let index = self.get_next_4_bytes() as usize;
                    self.memory[index] = pop!().unwrap();
                },
                Instr::LOAD => {
                    let index = self.get_next_4_bytes() as usize;
                    push!(self.memory[index]);
                },
                Instr::PRINT => {
                    println!("PRINT: {}", pop!().unwrap());
                },
                Instr::DUMP_STACK => {
                    println!("{:?}", self.stack);
                },
                Instr::DUMP_GLOBALS => {
                    println!("{:?}", self.memory);},
            }
        }
    }

    fn get_next_4_bytes(&mut self) -> u32 {
        let val = (self.bytecode[self.program_counter] as u32) << 24 |
                  (self.bytecode[self.program_counter + 1] as u32) << 16 |
                  (self.bytecode[self.program_counter + 2] as u32) << 8 |
                  (self.bytecode[self.program_counter + 3] as u32);
        self.program_counter += 4;
        debug!("get_next_4_bytes: 0x{:04X}", val);
        val
    }
}

// TODO: Add tests
<|endoftext|>


<commit_before>use arbitrary::Arbitrary;
use once_cell::unsync::OnceCell;

#[cfg(debug_assertions)]
fn unreachable<T>() -> T {
    unreachable!()
}

#[cfg(not(debug_assertions))]
fn unreachable<T>() -> T {
    unsafe { std::hint::unreachable_unchecked() }
}

pub enum NoError {}

pub trait LazyTransform {
    type Input;
    type Output;
    type Error;

    fn lazy_transform(input: &Self::Input) -> Result<Self::Output, Self::Error>;
}

pub struct LazyMut<L: LazyTransform> {
    input: Option<L::Input>,
    output: OnceCell<L::Output>,
}

impl<L: LazyTransform> std::fmt::Debug for LazyMut<L>
where
    L::Input: std::fmt::Debug,
    L::Output: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("LazyMut")
            .field("input", &self.input_opt())
            .field("output", &self.output_opt())
            .finish()
    }
}

impl<L: 'static + LazyTransform> Arbitrary for LazyMut<L>
where
    L::Output: Arbitrary,
{
    fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Self> {
        L::Output::arbitrary(u).map(LazyMut::new_from_output)
    }

    fn arbitrary_take_rest(u: arbitrary::Unstructured) -> arbitrary::Result<Self> {
        L::Output::arbitrary_take_rest(u).map(LazyMut::new_from_output)
    }

    fn size_hint(depth: usize) -> (usize, Option<usize>) {
        L::Output::size_hint(depth)
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        match self.output.get() {
            Some(output) => Box::new(output.shrink().map(LazyMut::new_from_output)),
            None => Box::new(std::iter::empty()),
        }
    }
}

impl<L: LazyTransform> Default for LazyMut<L>
where
    L::Input: Default,
    L::Output: Default,
{
    fn default() -> Self {
        Self::new_with_output_unchecked(Default::default(), Default::default())
    }
}

impl<L: LazyTransform> LazyMut<L> {
    pub fn new(input: L::Input) -> Self {
        LazyMut {
            input: Some(input),
            output: OnceCell::new(),
        }
    }

    pub fn new_from_output(output: L::Output) -> Self {
        LazyMut {
            input: None,
            output: OnceCell::from(output),
        }
    }

    pub fn new_with_output_unchecked(input: L::Input, output: L::Output) -> Self {
        LazyMut {
            input: Some(input),
            output: OnceCell::from(output),
        }
    }

    pub fn input_opt(&self) -> Option<&L::Input> {
        self.input.as_ref()
    }

    pub fn input_res(&self) -> Result<&L::Input, &L::Output> {
        self.input_opt()
            .ok_or_else(|| self.output_opt().unwrap_or_else(unreachable))
    }

    pub fn output_opt(&self) -> Option<&L::Output> {
        self.output.get()
    }

    pub fn output_opt_mut(&mut self) -> Option<&mut L::Output> {
        self.input = None;
        self.output.get_mut()
    }

    pub fn set_output(&mut self, output: L::Output) {
        self.input = None;
        self.output = OnceCell::from(output);
    }

    pub fn try_output(&self) -> Result<&L::Output, L::Error> {
        let input = &self.input;
        self.output
            .get_or_try_init(|| L::lazy_transform(input.as_ref().unwrap_or_else(unreachable)))
    }

    pub fn try_output_mut(&mut self) -> Result<&mut L::Output, L::Error> {
        self.try_output()?;
        self.output_opt_mut().ok_or_else(unreachable)
    }

    pub fn try_into_output(self) -> Result<L::Output, L::Error> {
        self.try_output()?;
        self.output.into_inner().ok_or_else(unreachable)
    }
}

impl<L: LazyTransform<Error = NoError>> LazyMut<L> {
    pub fn output(&self) -> &L::Output {
        self.try_output().unwrap_or_else(|err| match err {})
    }

    pub fn output_mut(&mut self) -> &mut L::Output {
        self.try_output_mut().unwrap_or_else(|err| match err {})
    }

    pub fn into_output(self) -> L::Output {
        self.try_into_output().unwrap_or_else(|err| match err {})
    }
}

impl<L: LazyTransform<Error = NoError>> std::ops::Deref for LazyMut<L> {
    type Target = L::Output;

    fn deref(&self) -> &L::Output {
        self.output()
    }
}

impl<L: LazyTransform<Error = NoError>> std::ops::DerefMut for LazyMut<L> {
    fn deref_mut(&mut self) -> &mut L::Output {
        self.output_mut()
    }
}

impl<L: LazyTransform> PartialEq for LazyMut<L>
where
    L::Input: PartialEq,
    L::Output: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        if let (Some(a), Some(b)) = (self.input_opt(), other.input_opt()) {
            return a == b;
        }
        match (self.try_output(), other.try_output()) {
            (Ok(a), Ok(b)) => a == b,

            // If one of the transforms errored out, treat containers as unequal.
            (Ok(_), Err(_)) | (Err(_), Ok(_)) => false,

            // We can't reach this because it would mean we tried to
            // invoke transform on both containers, which, in turn,
            // means they both were in "input" state, which would be
            // handled by the first check in this function.
            (Err(_), Err(_)) => unreachable(),
        }
    }
}

impl<L: LazyTransform> Eq for LazyMut<L>
where
    L::Input: Eq,
    L::Output: Eq,
{
}

impl<L: LazyTransform> std::hash::Hash for LazyMut<L>
where
    L::Output: std::hash::Hash,
{
    fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
        // Unlike in case with equality, we must take a hash of the output
        // here so that we can find some value later when it's evaluated.
        self.try_output().ok().hash(h)
    }
}

impl<L: LazyTransform> Clone for LazyMut<L>
where
    L::Input: Clone,
    L::Output: Clone,
{
    fn clone(&self) -> Self {
        LazyMut {
            input: self.input.clone(),
            output: self.output.clone(),
        }
    }
}
<commit_msg>Fix LazyMut equality check<commit_after>use arbitrary::Arbitrary;
use once_cell::unsync::OnceCell;

#[cfg(debug_assertions)]
fn unreachable<T>() -> T {
    unreachable!()
}

#[cfg(not(debug_assertions))]
fn unreachable<T>() -> T {
    unsafe { std::hint::unreachable_unchecked() }
}

pub enum NoError {}

pub trait LazyTransform {
    type Input;
    type Output;
    type Error;

    fn lazy_transform(input: &Self::Input) -> Result<Self::Output, Self::Error>;
}

pub struct LazyMut<L: LazyTransform> {
    input: Option<L::Input>,
    output: OnceCell<L::Output>,
}

impl<L: LazyTransform> std::fmt::Debug for LazyMut<L>
where
    L::Input: std::fmt::Debug,
    L::Output: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("LazyMut")
            .field("input", &self.input_opt())
            .field("output", &self.output_opt())
            .finish()
    }
}

impl<L: 'static + LazyTransform> Arbitrary for LazyMut<L>
where
    L::Output: Arbitrary,
{
    fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<Self> {
        L::Output::arbitrary(u).map(LazyMut::new_from_output)
    }

    fn arbitrary_take_rest(u: arbitrary::Unstructured) -> arbitrary::Result<Self> {
        L::Output::arbitrary_take_rest(u).map(LazyMut::new_from_output)
    }

    fn size_hint(depth: usize) -> (usize, Option<usize>) {
        L::Output::size_hint(depth)
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        match self.output.get() {
            Some(output) => Box::new(output.shrink().map(LazyMut::new_from_output)),
            None => Box::new(std::iter::empty()),
        }
    }
}

impl<L: LazyTransform> Default for LazyMut<L>
where
    L::Input: Default,
    L::Output: Default,
{
    fn default() -> Self {
        Self::new_with_output_unchecked(Default::default(), Default::default())
    }
}

impl<L: LazyTransform> LazyMut<L> {
    pub fn new(input: L::Input) -> Self {
        LazyMut {
            input: Some(input),
            output: OnceCell::new(),
        }
    }

    pub fn new_from_output(output: L::Output) -> Self {
        LazyMut {
            input: None,
            output: OnceCell::from(output),
        }
    }

    pub fn new_with_output_unchecked(input: L::Input, output: L::Output) -> Self {
        LazyMut {
            input: Some(input),
            output: OnceCell::from(output),
        }
    }

    pub fn input_opt(&self) -> Option<&L::Input> {
        self.input.as_ref()
    }

    pub fn input_res(&self) -> Result<&L::Input, &L::Output> {
        self.input_opt()
            .ok_or_else(|| self.output_opt().unwrap_or_else(unreachable))
    }

    pub fn output_opt(&self) -> Option<&L::Output> {
        self.output.get()
    }

    pub fn output_opt_mut(&mut self) -> Option<&mut L::Output> {
        self.input = None;
        self.output.get_mut()
    }

    pub fn set_output(&mut self, output: L::Output) {
        self.input = None;
        self.output = OnceCell::from(output);
    }

    pub fn try_output(&self) -> Result<&L::Output, L::Error> {
        let input = &self.input;
        self.output
            .get_or_try_init(|| L::lazy_transform(input.as_ref().unwrap_or_else(unreachable)))
    }

    pub fn try_output_mut(&mut self) -> Result<&mut L::Output, L::Error> {
        self.try_output()?;
        self.output_opt_mut().ok_or_else(unreachable)
    }

    pub fn try_into_output(self) -> Result<L::Output, L::Error> {
        self.try_output()?;
        self.output.into_inner().ok_or_else(unreachable)
    }
}

impl<L: LazyTransform<Error = NoError>> LazyMut<L> {
    pub fn output(&self) -> &L::Output {
        self.try_output().unwrap_or_else(|err| match err {})
    }

    pub fn output_mut(&mut self) -> &mut L::Output {
        self.try_output_mut().unwrap_or_else(|err| match err {})
    }

    pub fn into_output(self) -> L::Output {
        self.try_into_output().unwrap_or_else(|err| match err {})
    }
}

impl<L: LazyTransform<Error = NoError>> std::ops::Deref for LazyMut<L> {
    type Target = L::Output;

    fn deref(&self) -> &L::Output {
        self.output()
    }
}

impl<L: LazyTransform<Error = NoError>> std::ops::DerefMut for LazyMut<L> {
    fn deref_mut(&mut self) -> &mut L::Output {
        self.output_mut()
    }
}

impl<L: LazyTransform> PartialEq for LazyMut<L>
where
    L::Input: PartialEq,
    L::Output: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        // Fast path: both LazyMuts are in the "input" state and inputs are equal.
        // Assume that outputs will be equal too, and don't invoke transforms.
        // If inputs are not equal, it doesn't yet mean that outputs are not equal
        // too, so carry on with full output comparison.
        if let (Some(a), Some(b)) = (self.input_opt(), other.input_opt()) {
            if a == b {
                return true;
            }
        }
        // Slower path: inputs are not equal or at least one of the LazyMuts
        // is in the "output" state.
        match (self.try_output(), other.try_output()) {
            (Ok(a), Ok(b)) => a == b,
            // If at least one of the transforms errored out, treat containers
            // as unequal.
            _ => false,
        }
    }
}

impl<L: LazyTransform> Eq for LazyMut<L>
where
    L::Input: Eq,
    L::Output: Eq,
{
}

impl<L: LazyTransform> std::hash::Hash for LazyMut<L>
where
    L::Output: std::hash::Hash,
{
    fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
        // Unlike in case with equality, we must take a hash of the output
        // here so that we can find some value later when it's evaluated.
        self.try_output().ok().hash(h)
    }
}

impl<L: LazyTransform> Clone for LazyMut<L>
where
    L::Input: Clone,
    L::Output: Clone,
{
    fn clone(&self) -> Self {
        LazyMut {
            input: self.input.clone(),
            output: self.output.clone(),
        }
    }
}
<|endoftext|>


<commit_before>//! Command part of IPC

use std::io::prelude::*;
use std::collections::BTreeMap;

use rustc_serialize::json::{encode, Json, ToJson, ParserError};

use super::channel::{self, ReceiveError};

use registry;
use commands;

macro_rules! expect_key {
    ($in_json:expr; $name:expr, $typ:ident) => {
        match $in_json.remove($name) {
            Some(key) => match key {
                Json::$typ(var) => var,
                _ => return Err(channel::error_expecting_key($name,
                          stringify!($typ)))
            },
            None => return Err(channel::error_expecting_key($name,
            stringify!($typ)))
        }
    }
}

/// Run a thread reading and replying to queries
pub fn thread<S: Read + Write>(mut stream: S) {
    loop {
        match channel::read_packet(&mut stream) {
            Ok(packet) => {
                trace!("Read packet: {}", encode(&packet)
                    .unwrap_or("<packet that was read already??>".to_string()));
                // Error half of result is discarded but isn't very relevant
                let reply = reply(packet).unwrap_or_else(|e| e);
                trace!("Writing reply: {}", encode(&reply)
                       .unwrap_or("<a reply which is not writable>".to_string()));
                channel::write_packet(&mut stream, &reply)
                    .expect("response: Unable to reply!");
            },
            Err(read_err) => match read_err {
                ReceiveError::IO(ioerr) => {
                    warn!("Unable to read reply! Closing connection.");
                    debug!("Got IOError: {:?}", ioerr);
                    return;
                },
                ReceiveError::InvalidJson(parse_err) => match parse_err {
                    ParserError::SyntaxError(code, start, end) => {
                        let reply = Json::Object(json_object!{
                            "type" => "error",
                            "reason" => "invalid json",
                            "code" => (format!("{:?}", code)),
                            "start" => (start as u64),
                            "end" => (end as u64)
                        });
                        channel::write_packet(&mut stream, &reply)
                            .expect("invalid syntax: Unaable to reply!");
                    }
                    // Should not be ParserError::IOError...
                    _ => unreachable!()
                }
            }
        }
    }
}

/// Generates the response needed to a given command
/// If the request is invalid it returns an Err.
/// If the request is valid but fails it returns an Ok.
pub fn reply(json: Json) -> Result<Json, Json> {
    let mut object: BTreeMap<String, Json>;
    if let Json::Object(obj) = json {
        object = obj;
    }
    else {
        return Err(channel::error_json(
            "invalid format - object required".to_string()))
    }

    let request_type = expect_key!(object; "type", String);

    // Converts the string to a str in the most Rustic way possible
    match &*request_type {
        // Registry
        "get" => {
            use std::ops::Deref;
            use registry::RegistryError::*;

            let key = expect_key!(object; "key", String);

            match registry::get_data(&key) {
                Ok(data) => {
                    let (flags, arc) = data.resolve();
                    let reply = channel::success_json_with(json_object! {
                        "value" => (arc.deref().clone()),
                        "flags" => flags
                    });
                    // I'd return a Cow<Json> because write_packet needs an
                    // &Json, but I dunno how to move the fields over in a
                    // borrow.
                    return Ok(reply);
                },
                Err(err) => match err {
                    KeyNotFound =>
                        return Err(channel::error_json("key not found".to_string())),
                    InvalidOperation =>
                        return Err(channel::error_json("cannot get that key".to_string())),
                }
            }
        },
        "set" => {
            use registry::RegistryError::*;

            let key = expect_key!(&mut object; "key", String);
            let value: Json;
            match object.remove("value") {
                Some(val) => value = val,
                None => return Err(channel::error_expecting_key("value", "any"))
            }

            let reg_set = try!(registry::set_json(key, value.clone())
                 .map_err(|e| match e {
                     InvalidOperation =>
                         channel::error_json("cannot set that key".to_string()),
                     KeyNotFound =>
                         channel::error_json("key not found, use insert".to_string())
                 }));
            reg_set.call(value);

            Ok(channel::success_json())
        },
        "exists" => {
            let key = expect_key!(&mut object; "key", String);

            let (type_, flags) = try!(registry::key_info(&key).ok_or(
                channel::success_json_with(json_object!{ "exists" => false })));

            Ok(channel::success_json_with(json_object!{
                "exists" => true,
                "flags" => flags,
                "type" => type_
            }))
        },

        // Commands
        "run" => {
            let key = expect_key!(&mut object; "key", String);

            let command = try!(commands::get(&key).ok_or(
                channel::error_json("command not found".to_string())));

            command();

            Ok(channel::success_json())
        },

        // Meta/API commands
        "version" => {
            Ok(channel::value_json(Json::U64(super::VERSION)))
        },

        "commands" => {
            Ok(channel::value_json(Json::Array([
                "get", "set", "exists", "run",
                "version", "commands", "ping",
                ].into_iter().map(|v | Json::String(v.to_string())).collect())))
        },

        "ping" => {
            Ok(channel::success_json())
        },

        _ => Err(channel::error_json("invalid request; see 'commands'".to_string()))
    }
}
<commit_msg>Changed command methods to json macro<commit_after>//! Command part of IPC

use std::io::prelude::*;
use std::collections::BTreeMap;

use rustc_serialize::json::{encode, Json, ToJson, ParserError};

use super::channel::{self, ReceiveError};

use registry;
use commands;

macro_rules! expect_key {
    ($in_json:expr; $name:expr, $typ:ident) => {
        match $in_json.remove($name) {
            Some(key) => match key {
                Json::$typ(var) => var,
                _ => return Err(channel::error_expecting_key($name,
                          stringify!($typ)))
            },
            None => return Err(channel::error_expecting_key($name,
            stringify!($typ)))
        }
    }
}

/// Run a thread reading and replying to queries
pub fn thread<S: Read + Write>(mut stream: S) {
    loop {
        match channel::read_packet(&mut stream) {
            Ok(packet) => {
                trace!("Read packet: {}", encode(&packet)
                    .unwrap_or("<packet that was read already??>".to_string()));
                // Error half of result is discarded but isn't very relevant
                let reply = reply(packet).unwrap_or_else(|e| e);
                trace!("Writing reply: {}", encode(&reply)
                       .unwrap_or("<a reply which is not writable>".to_string()));
                channel::write_packet(&mut stream, &reply)
                    .expect("response: Unable to reply!");
            },
            Err(read_err) => match read_err {
                ReceiveError::IO(ioerr) => {
                    warn!("Unable to read reply! Closing connection.");
                    debug!("Got IOError: {:?}", ioerr);
                    return;
                },
                ReceiveError::InvalidJson(parse_err) => match parse_err {
                    ParserError::SyntaxError(code, start, end) => {
                        let reply = Json::Object(json_object!{
                            "type" => "error",
                            "reason" => "invalid json",
                            "code" => (format!("{:?}", code)),
                            "start" => (start as u64),
                            "end" => (end as u64)
                        });
                        channel::write_packet(&mut stream, &reply)
                            .expect("invalid syntax: Unaable to reply!");
                    }
                    // Should not be ParserError::IOError...
                    _ => unreachable!()
                }
            }
        }
    }
}

/// Generates the response needed to a given command
/// If the request is invalid it returns an Err.
/// If the request is valid but fails it returns an Ok.
pub fn reply(json: Json) -> Result<Json, Json> {
    let mut object: BTreeMap<String, Json>;
    if let Json::Object(obj) = json {
        object = obj;
    }
    else {
        return Err(channel::error_json(
            "invalid format - object required".to_string()))
    }

    let request_type = expect_key!(object; "type", String);

    // Converts the string to a str in the most Rustic way possible
    match &*request_type {
        // Registry
        "get" => {
            use std::ops::Deref;
            use registry::RegistryError::*;

            let key = expect_key!(object; "key", String);

            match registry::get_data(&key) {
                Ok(data) => {
                    let (flags, arc) = data.resolve();
                    let reply = channel::value_json(arc.deref().clone());
                    // I'd return a Cow<Json> because write_packet needs an
                    // &Json, but I dunno how to move the fields over in a
                    // borrow.
                    return Ok(reply);
                },
                Err(err) => match err {
                    KeyNotFound =>
                        return Err(channel::error_json("key not found".to_string())),
                    InvalidOperation =>
                        return Err(channel::error_json("cannot get that key".to_string())),
                }
            }
        },
        "set" => {
            use registry::RegistryError::*;

            let key = expect_key!(&mut object; "key", String);
            let value: Json;
            match object.remove("value") {
                Some(val) => value = val,
                None => return Err(channel::error_expecting_key("value", "any"))
            }

            let reg_set = try!(registry::set_json(key, value.clone())
                 .map_err(|e| match e {
                     InvalidOperation =>
                         channel::error_json("cannot set that key".to_string()),
                     KeyNotFound =>
                         channel::error_json("key not found, use insert".to_string())
                 }));
            reg_set.call(value);

            Ok(channel::success_json())
        },
        "exists" => {
            let key = expect_key!(&mut object; "key", String);

            let (type_, flags) = try!(registry::key_info(&key).ok_or(
                channel::success_json_with(json_object!{ "exists" => false })));

            Ok(channel::success_json_with(json_object!{
                "exists" => true,
                "flags" => flags,
                "type" => type_
            }))
        },

        // Commands
        "run" => {
            let key = expect_key!(&mut object; "key", String);

            let command = try!(commands::get(&key).ok_or(
                channel::error_json("command not found".to_string())));

            command();

            Ok(channel::success_json())
        },

        // Meta/API commands
        "version" => {
            Ok(channel::value_json(Json::U64(super::VERSION)))
        },

        "commands" => {
            Ok(channel::value_json(Json::Array([
                "get", "set", "exists", "run",
                "version", "commands", "ping",
                ].into_iter().map(|v | Json::String(v.to_string())).collect())))
        },

        "ping" => {
            Ok(channel::success_json())
        },

        _ => Err(channel::error_json("invalid request; see 'commands'".to_string()))
    }
}
<|endoftext|>


<commit_before>use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation};
use crate::borrow_check::places_conflict;
use crate::borrow_check::AccessDepth;
use crate::dataflow::indexes::BorrowIndex;
use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase};
use rustc::mir::{ProjectionElem, BorrowKind};
use rustc::ty::TyCtxt;
use rustc_data_structures::graph::dominators::Dominators;

/// Returns `true` if the borrow represented by `kind` is
/// allowed to be split into separate Reservation and
/// Activation phases.
pub(super) fn allow_two_phase_borrow<'a, 'tcx, 'gcx: 'tcx>(kind: BorrowKind) -> bool {
    kind.allows_two_phase_borrow()
}

/// Control for the path borrow checking code
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(super) enum Control {
    Continue,
    Break,
}

/// Encapsulates the idea of iterating over every borrow that involves a particular path
pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
    s: &mut S,
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
    mir: &Mir<'tcx>,
    _location: Location,
    access_place: (AccessDepth, &Place<'tcx>),
    borrow_set: &BorrowSet<'tcx>,
    candidates: I,
    mut op: F,
) where
    F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
    I: Iterator<Item=BorrowIndex>
{
    let (access, place) = access_place;

    // FIXME: analogous code in check_loans first maps `place` to
    // its base_path.

    // check for loan restricting path P being used. Accounts for
    // borrows of P, P.a.b, etc.
    for i in candidates {
        let borrowed = &borrow_set[i];

        if places_conflict::borrow_conflicts_with_place(
            tcx,
            mir,
            &borrowed.borrowed_place,
            borrowed.kind,
            place,
            access,
            places_conflict::PlaceConflictBias::Overlap,
        ) {
            debug!(
                "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
                i, borrowed, place, access
            );
            let ctrl = op(s, i, borrowed);
            if ctrl == Control::Break {
                return;
            }
        }
    }
}

pub(super) fn is_active<'tcx>(
    dominators: &Dominators<BasicBlock>,
    borrow_data: &BorrowData<'tcx>,
    location: Location
) -> bool {
    debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location);

    let activation_location = match borrow_data.activation_location {
        // If this is not a 2-phase borrow, it is always active.
        TwoPhaseActivation::NotTwoPhase => return true,
        // And if the unique 2-phase use is not an activation, then it is *never* active.
        TwoPhaseActivation::NotActivated => return false,
        // Otherwise, we derive info from the activation point `loc`:
        TwoPhaseActivation::ActivatedAt(loc) => loc,
    };

    // Otherwise, it is active for every location *except* in between
    // the reservation and the activation:
    //
    //       X
    //      /
    //     R      <--+ Except for this
    //    / \        | diamond
    //    \ /        |
    //     A  <------+
    //     |
    //     Z
    //
    // Note that we assume that:
    // - the reservation R dominates the activation A
    // - the activation A post-dominates the reservation R (ignoring unwinding edges).
    //
    // This means that there can't be an edge that leaves A and
    // comes back into that diamond unless it passes through R.
    //
    // Suboptimal: In some cases, this code walks the dominator
    // tree twice when it only has to be walked once. I am
    // lazy. -nmatsakis

    // If dominated by the activation A, then it is active. The
    // activation occurs upon entering the point A, so this is
    // also true if location == activation_location.
    if activation_location.dominates(location, dominators) {
        return true;
    }

    // The reservation starts *on exiting* the reservation block,
    // so check if the location is dominated by R.successor. If so,
    // this point falls in between the reservation and location.
    let reserve_location = borrow_data.reserve_location.successor_within_block();
    if reserve_location.dominates(location, dominators) {
        false
    } else {
        // Otherwise, this point is outside the diamond, so
        // consider the borrow active. This could happen for
        // example if the borrow remains active around a loop (in
        // which case it would be active also for the point R,
        // which would generate an error).
        true
    }
}

/// Determines if a given borrow is borrowing local data
/// This is called for all Yield statements on movable generators
pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
    match place {
        Place::Base(PlaceBase::Static(..)) => false,
        Place::Base(PlaceBase::Local(..)) => true,
        Place::Projection(box proj) => {
            match proj.elem {
                // Reborrow of already borrowed data is ignored
                // Any errors will be caught on the initial borrow
                ProjectionElem::Deref => false,

                // For interior references and downcasts, find out if the base is local
                ProjectionElem::Field(..)
                    | ProjectionElem::Index(..)
                    | ProjectionElem::ConstantIndex { .. }
                | ProjectionElem::Subslice { .. }
                | ProjectionElem::Downcast(..) => borrow_of_local_data(&proj.base),
            }
        }
    }
}
<commit_msg>Rollup merge of #61093 - spastorino:borrow-of-local-data-iterate, r=oli-obk<commit_after>use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation};
use crate::borrow_check::places_conflict;
use crate::borrow_check::AccessDepth;
use crate::dataflow::indexes::BorrowIndex;
use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase};
use rustc::mir::{ProjectionElem, BorrowKind};
use rustc::ty::TyCtxt;
use rustc_data_structures::graph::dominators::Dominators;

/// Returns `true` if the borrow represented by `kind` is
/// allowed to be split into separate Reservation and
/// Activation phases.
pub(super) fn allow_two_phase_borrow<'a, 'tcx, 'gcx: 'tcx>(kind: BorrowKind) -> bool {
    kind.allows_two_phase_borrow()
}

/// Control for the path borrow checking code
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(super) enum Control {
    Continue,
    Break,
}

/// Encapsulates the idea of iterating over every borrow that involves a particular path
pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> (
    s: &mut S,
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
    mir: &Mir<'tcx>,
    _location: Location,
    access_place: (AccessDepth, &Place<'tcx>),
    borrow_set: &BorrowSet<'tcx>,
    candidates: I,
    mut op: F,
) where
    F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
    I: Iterator<Item=BorrowIndex>
{
    let (access, place) = access_place;

    // FIXME: analogous code in check_loans first maps `place` to
    // its base_path.

    // check for loan restricting path P being used. Accounts for
    // borrows of P, P.a.b, etc.
    for i in candidates {
        let borrowed = &borrow_set[i];

        if places_conflict::borrow_conflicts_with_place(
            tcx,
            mir,
            &borrowed.borrowed_place,
            borrowed.kind,
            place,
            access,
            places_conflict::PlaceConflictBias::Overlap,
        ) {
            debug!(
                "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
                i, borrowed, place, access
            );
            let ctrl = op(s, i, borrowed);
            if ctrl == Control::Break {
                return;
            }
        }
    }
}

pub(super) fn is_active<'tcx>(
    dominators: &Dominators<BasicBlock>,
    borrow_data: &BorrowData<'tcx>,
    location: Location
) -> bool {
    debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location);

    let activation_location = match borrow_data.activation_location {
        // If this is not a 2-phase borrow, it is always active.
        TwoPhaseActivation::NotTwoPhase => return true,
        // And if the unique 2-phase use is not an activation, then it is *never* active.
        TwoPhaseActivation::NotActivated => return false,
        // Otherwise, we derive info from the activation point `loc`:
        TwoPhaseActivation::ActivatedAt(loc) => loc,
    };

    // Otherwise, it is active for every location *except* in between
    // the reservation and the activation:
    //
    //       X
    //      /
    //     R      <--+ Except for this
    //    / \        | diamond
    //    \ /        |
    //     A  <------+
    //     |
    //     Z
    //
    // Note that we assume that:
    // - the reservation R dominates the activation A
    // - the activation A post-dominates the reservation R (ignoring unwinding edges).
    //
    // This means that there can't be an edge that leaves A and
    // comes back into that diamond unless it passes through R.
    //
    // Suboptimal: In some cases, this code walks the dominator
    // tree twice when it only has to be walked once. I am
    // lazy. -nmatsakis

    // If dominated by the activation A, then it is active. The
    // activation occurs upon entering the point A, so this is
    // also true if location == activation_location.
    if activation_location.dominates(location, dominators) {
        return true;
    }

    // The reservation starts *on exiting* the reservation block,
    // so check if the location is dominated by R.successor. If so,
    // this point falls in between the reservation and location.
    let reserve_location = borrow_data.reserve_location.successor_within_block();
    if reserve_location.dominates(location, dominators) {
        false
    } else {
        // Otherwise, this point is outside the diamond, so
        // consider the borrow active. This could happen for
        // example if the borrow remains active around a loop (in
        // which case it would be active also for the point R,
        // which would generate an error).
        true
    }
}

/// Determines if a given borrow is borrowing local data
/// This is called for all Yield statements on movable generators
pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
    place.iterate(|place_base, place_projection| {
        match place_base {
            PlaceBase::Static(..) => return false,
            PlaceBase::Local(..) => {},
        }

        for proj in place_projection {
            // Reborrow of already borrowed data is ignored
            // Any errors will be caught on the initial borrow
            if proj.elem == ProjectionElem::Deref {
                return false;
            }
        }

        true
    })
}
<|endoftext|>


<commit_before>extern crate serde_json;

use errors::*;
use jira_request::*;
use reqwest;
use reqwest::header::Headers;
use reqwest::Response;
use reqwest::StatusCode;
use std::io::Read;

pub fn send<R: JIRARequest>(request: R) -> Result<R::Response> {
    let client = reqwest::Client::new().unwrap();

    let url = format!("{}{}", &request.base_url(), &request.path());

    let mut res: Response = client.request(request.method(), &url)
        .headers(request.headers().unwrap_or(Headers::new()))
        .json(&request.body().unwrap_or("".to_string()))
        .send()
        .chain_err(|| "Failed to request JIRA")?;

    info!("Status: {}", res.status());
    info!("Headers:\n{}", res.headers());

    ::std::io::copy(&mut res, &mut ::std::io::stdout()).unwrap();

    let mut body = vec![];
    res.read_to_end(&mut body).unwrap();

    match res.status() {
        &StatusCode::Ok => {
            serde_json::from_str::<R::Response>(&String::from_utf8_lossy(&body).into_owned())
                .chain_err(|| "Failed to deserialize to the struct")
        }
        _ => bail!(String::from_utf8_lossy(&body).to_string()),
    }
}<commit_msg>:fire: Remove std::io<commit_after>extern crate serde_json;

use errors::*;
use jira_request::*;
use reqwest;
use reqwest::header::Headers;
use reqwest::Response;
use reqwest::StatusCode;
use std::io::Read;

pub fn send<R: JIRARequest>(request: R) -> Result<R::Response> {
    let client = reqwest::Client::new().unwrap();

    let url = format!("{}{}", &request.base_url(), &request.path());

    let mut res: Response = client.request(request.method(), &url)
        .headers(request.headers().unwrap_or(Headers::new()))
        .json(&request.body().unwrap_or("".to_string()))
        .send()
        .chain_err(|| "Failed to request JIRA")?;

    info!("Status: {}", res.status());
    info!("Headers:\n{}", res.headers());

    let mut body = vec![];
    res.read_to_end(&mut body).unwrap();

    match res.status() {
        &StatusCode::Ok => {
            serde_json::from_str::<R::Response>(&String::from_utf8_lossy(&body).into_owned())
                .chain_err(|| "Failed to deserialize to the struct")
        }
        _ => bail!(String::from_utf8_lossy(&body).to_string()),
    }
}<|endoftext|>