<commit_before>extern crate ffmpeg;

use std::path::Path;

use std::collections::HashSet;

use std::rc::Weak;
use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use ffmpeg::format::stream::disposition::ATTACHED_PIC;

pub trait VideoNotifiable {
    fn new_video_frame(&mut self, &ffmpeg::frame::Video);
}
pub trait AudioNotifiable {
    fn new_audio_frame(&mut self, &ffmpeg::frame::Audio);
}

pub struct Context {
    pub ffmpeg_context: ffmpeg::format::context::Input,
    pub file_name: String,
    pub name: String,
    pub artist: String,
    pub title: String,
    pub duration: f64,
    pub description: String,

    pub video_stream: Option<usize>,
    pub video_decoder: Option<ffmpeg::codec::decoder::Video>,
    pub video_notifiables: Vec<Weak<RefCell<VideoNotifiable>>>,
    pub video_is_thumbnail: bool,

    pub audio_stream: Option<usize>,
    pub audio_decoder: Option<ffmpeg::codec::decoder::Audio>,
    pub audio_notifiables: Vec<Weak<RefCell<AudioNotifiable>>>,
}

impl Context {
    pub fn new(path: &PathBuf) -> Result<Context, String> {
        println!("\n*** Attempting to open {:?}", path);

        match ffmpeg::format::input(&path.as_path()) {
            Ok(ffmpeg_context) => {
                let mut new_ctx = Context{
                    file_name: String::from(path.file_name().unwrap().to_str().unwrap()),
                    name: String::from(path.file_stem().unwrap().to_str().unwrap()),
                    artist: String::new(),
                    title: String::new(),
                    duration: ffmpeg_context.duration() as f64 / ffmpeg::ffi::AV_TIME_BASE as f64,
                    description: String::new(),

                    video_stream: None,
                    video_decoder: None,
                    video_notifiables: Vec::new(),
                    video_is_thumbnail: false,

                    audio_stream: None,
                    audio_decoder: None,
                    audio_notifiables: Vec::new(),
                    ffmpeg_context: ffmpeg_context,
                };

                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.description = String::from(format.description());

                    new_ctx.init_video_decoder();
                    new_ctx.init_audio_decoder();
                    new_ctx.get_metadata();
                }

                // TODO: see what we should do with subtitles

                if new_ctx.video_stream.is_some() || new_ctx.audio_stream.is_some() {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

    pub fn init_video_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Video) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                if best_stream.disposition() & ATTACHED_PIC == ATTACHED_PIC {
                    self.video_is_thumbnail = true;
                    println!("\nFound thumbnail in stream with id: {}", stream_index);
                }
                else {
                    self.video_is_thumbnail = false;
                    println!("\nFound video stream with id: {}", stream_index);
                }
                best_stream
            },
            None => {
                println!("No video stream");
                return;
            },
        };

        match stream.codec().decoder().video() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed video decoder: {:?}", decoder.format());
                    },
                    Err(error) => panic!("Failed to set parameters for video decoder: {:?}", error),
                }

                println!("\tvideo decoder: {:?}, width: {}, height: {}",
                         decoder.format(), decoder.width(), decoder.height());
                self.video_stream = Some(stream_index);
                self.video_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get video decoder: {:?}", error),
        }
    }

    pub fn init_audio_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Audio) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                println!("\nFound audio stream with id: {}", stream_index);
                best_stream
            },
            None => {
                println!("No audio stream");
                return;
            },
        };

        match stream.codec().decoder().audio() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed audio decoder: {:?} - channels: {}", decoder.format(), decoder.channels());
                    },
                    Err(error) => panic!("Failed to set parameters for audio decoder: {:?}", error),
                }
                println!("\taudio decoder: {:?}, channels: {}, frame count: {}",
                         decoder.format(), decoder.channels(), decoder.frames());
                self.audio_stream = Some(stream_index);
                self.audio_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get audio decoder: {:?}", error),
        }
    }

    pub fn get_metadata(&mut self) {
	    for (k, v) in self.ffmpeg_context.metadata().iter() {
	        if k.to_lowercase() == "artist" {
	            self.artist = v.to_owned();
	        }
	        else if k.to_lowercase() == "title" {
	            self.title = v.to_owned();
	        }
	    }
	    if self.title.is_empty() {
            self.title = self.name.clone();
	    }

        // TODO: get chapters
    }

    pub fn register_video_notifiable(&mut self, notifiable: Rc<RefCell<VideoNotifiable>>) {
        self.video_notifiables.push(Rc::downgrade(&notifiable));
    }

    pub fn register_audio_notifiable(&mut self, notifiable: Rc<RefCell<AudioNotifiable>>) {
        self.audio_notifiables.push(Rc::downgrade(&notifiable));
    }

    pub fn preview(&mut self) {
        let mut stream_processed = HashSet::new();
        let mut expected_frames = 0;
        if self.video_stream.is_some() {
            expected_frames += 1;
        }
        if self.audio_stream.is_some() {
            expected_frames += 1;
        }

        let mut video_frame = ffmpeg::frame::Video::empty();
        let mut audio_frame = ffmpeg::frame::Audio::empty();

        for (stream, packet) in self.ffmpeg_context.packets() {
            //print_packet_content(&stream, &packet);
            let mut got_frame = false;
            let decoder = stream.codec().decoder();
            match decoder.medium() {
                ffmpeg::media::Type::Video => match self.video_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut video = match self.video_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting video decoder for stream {}", stream_index),
                            };
                            if stream_processed.contains(&stream_index) {
                                // stream already processed
                                continue;
                            }
                            match video.decode(&packet, &mut video_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = video_frame.planes();
                                    println!("\tdecoded video frame, got frame: {}", got_frame);
                                },
                                Err(error) => println!("Error decoding video packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                stream_processed.insert(stream_index);
                                for notifiable_weak in self.video_notifiables.iter() {
                                    match notifiable_weak.upgrade() {
                                        Some(notifiable) => {
                                            notifiable.borrow_mut().new_video_frame(&video_frame);
                                        },
                                        None => (),
                                    };
                                }

                                video_frame = ffmpeg::frame::Video::empty();
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No video decoder"),
                },
                ffmpeg::media::Type::Audio => match self.audio_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let ref mut audio = match self.audio_decoder.as_mut() {
                                Some(decoder) => decoder,
                                None => panic!("Error getting audio decoder for stream {}", stream_index),
                            };
                            if stream_processed.contains(&stream_index) {
                                // stream already processed
                                continue;
                            }
                            match audio.decode(&packet, &mut audio_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = audio_frame.planes();
                                    println!("\tdecoded audio frame, got frame: {}", got_frame);
                                },
                                Err(error) => panic!("Error decoding audio packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                stream_processed.insert(stream_index);
                                for notifiable_weak in self.audio_notifiables.iter() {
                                    match notifiable_weak.upgrade() {
                                        Some(notifiable) => {
                                            notifiable.borrow_mut().new_audio_frame(&audio_frame);
                                        },
                                        None => (),
                                    };
                                }

                                audio_frame = ffmpeg::frame::Audio::empty();
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No audio decoder"),
                },
                _ => (),
            }

            if stream_processed.len() == expected_frames {
                break;
            }
        }
    }
}

fn print_packet_content(stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
    println!("\n* Packet for {:?} stream: {}", stream.disposition(), stream.index());
    println!("\tsize: {} - duration: {}, is key: {}",
             packet.size(), packet.duration(), packet.is_key(),
    );
    match packet.pts() {
        Some(pts) => println!("\tpts: {}", pts),
        None => (),
    }
    match packet.dts() {
        Some(dts) => println!("\tdts: {}", dts),
        None => (),
    }
    if let Some(ref data) = packet.data() {
        println!("\tfound data with len: {}", data.len());
    }
    let side_data_iter = stream.side_data();
    let side_data_len = side_data_iter.size_hint().0;
    if side_data_len > 0 {
        println!("\tside data nb: {}", side_data_len);
    }
}
<commit_msg>Media Context: fix members visibility (#3)<commit_after>extern crate ffmpeg;

use std::path::Path;

use std::collections::HashSet;

use std::rc::Weak;
use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use ffmpeg::format::stream::disposition::ATTACHED_PIC;

pub trait VideoNotifiable {
    fn new_video_frame(&mut self, &ffmpeg::frame::Video);
}
pub trait AudioNotifiable {
    fn new_audio_frame(&mut self, &ffmpeg::frame::Audio);
}

pub struct Context {
    pub ffmpeg_context: ffmpeg::format::context::Input,
    pub file_name: String,
    pub name: String,
    pub artist: String,
    pub title: String,
    pub duration: f64,
    pub description: String,

    pub video_stream: Option<usize>,
    pub video_decoder: Option<ffmpeg::codec::decoder::Video>,
    video_notifiables: Vec<Weak<RefCell<VideoNotifiable>>>,
    pub video_is_thumbnail: bool,

    pub audio_stream: Option<usize>,
    pub audio_decoder: Option<ffmpeg::codec::decoder::Audio>,
    audio_notifiables: Vec<Weak<RefCell<AudioNotifiable>>>,
}

impl Context {
    pub fn new(path: &PathBuf) -> Result<Context, String> {
        println!("\n*** Attempting to open {:?}", path);

        match ffmpeg::format::input(&path.as_path()) {
            Ok(ffmpeg_context) => {
                let mut new_ctx = Context{
                    file_name: String::from(path.file_name().unwrap().to_str().unwrap()),
                    name: String::from(path.file_stem().unwrap().to_str().unwrap()),
                    artist: String::new(),
                    title: String::new(),
                    duration: ffmpeg_context.duration() as f64 / ffmpeg::ffi::AV_TIME_BASE as f64,
                    description: String::new(),

                    video_stream: None,
                    video_decoder: None,
                    video_notifiables: Vec::new(),
                    video_is_thumbnail: false,

                    audio_stream: None,
                    audio_decoder: None,
                    audio_notifiables: Vec::new(),
                    ffmpeg_context: ffmpeg_context,
                };

                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.description = String::from(format.description());

                    new_ctx.init_video_decoder();
                    new_ctx.init_audio_decoder();
                    new_ctx.init_metadata();
                }

                // TODO: see what we should do with subtitles

                if new_ctx.video_stream.is_some() || new_ctx.audio_stream.is_some() {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

    fn init_video_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Video) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                if best_stream.disposition() & ATTACHED_PIC == ATTACHED_PIC {
                    self.video_is_thumbnail = true;
                    println!("\nFound thumbnail in stream with id: {}", stream_index);
                }
                else {
                    self.video_is_thumbnail = false;
                    println!("\nFound video stream with id: {}", stream_index);
                }
                best_stream
            },
            None => {
                println!("No video stream");
                return;
            },
        };

        match stream.codec().decoder().video() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed video decoder: {:?}", decoder.format());
                    },
                    Err(error) => panic!("Failed to set parameters for video decoder: {:?}", error),
                }

                println!("\tvideo decoder: {:?}, width: {}, height: {}",
                         decoder.format(), decoder.width(), decoder.height());
                self.video_stream = Some(stream_index);
                self.video_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get video decoder: {:?}", error),
        }
    }

    fn init_audio_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Audio) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                println!("\nFound audio stream with id: {}", stream_index);
                best_stream
            },
            None => {
                println!("No audio stream");
                return;
            },
        };

        match stream.codec().decoder().audio() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed audio decoder: {:?} - channels: {}", decoder.format(), decoder.channels());
                    },
                    Err(error) => panic!("Failed to set parameters for audio decoder: {:?}", error),
                }
                println!("\taudio decoder: {:?}, channels: {}, frame count: {}",
                         decoder.format(), decoder.channels(), decoder.frames());
                self.audio_stream = Some(stream_index);
                self.audio_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get audio decoder: {:?}", error),
        }
    }

    fn init_metadata(&mut self) {
	    for (k, v) in self.ffmpeg_context.metadata().iter() {
	        if k.to_lowercase() == "artist" {
	            self.artist = v.to_owned();
	        }
	        else if k.to_lowercase() == "title" {
	            self.title = v.to_owned();
	        }
	    }
	    if self.title.is_empty() {
            self.title = self.name.clone();
	    }

        // TODO: get chapters
    }

    pub fn register_video_notifiable(&mut self, notifiable: Rc<RefCell<VideoNotifiable>>) {
        self.video_notifiables.push(Rc::downgrade(&notifiable));
    }

    pub fn register_audio_notifiable(&mut self, notifiable: Rc<RefCell<AudioNotifiable>>) {
        self.audio_notifiables.push(Rc::downgrade(&notifiable));
    }

    pub fn preview(&mut self) {
        let mut stream_processed = HashSet::new();
        let mut expected_frames = 0;
        if self.video_stream.is_some() {
            expected_frames += 1;
        }
        if self.audio_stream.is_some() {
            expected_frames += 1;
        }

        let mut video_frame = ffmpeg::frame::Video::empty();
        let mut audio_frame = ffmpeg::frame::Audio::empty();

        for (stream, packet) in self.ffmpeg_context.packets() {
            //print_packet_content(&stream, &packet);
            let mut got_frame = false;
            let decoder = stream.codec().decoder();
            match decoder.medium() {
                ffmpeg::media::Type::Video => match self.video_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut video = match self.video_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting video decoder for stream {}", stream_index),
                            };
                            if stream_processed.contains(&stream_index) {
                                // stream already processed
                                continue;
                            }
                            match video.decode(&packet, &mut video_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = video_frame.planes();
                                    println!("\tdecoded video frame, got frame: {}", got_frame);
                                },
                                Err(error) => println!("Error decoding video packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                stream_processed.insert(stream_index);
                                for notifiable_weak in self.video_notifiables.iter() {
                                    match notifiable_weak.upgrade() {
                                        Some(notifiable) => {
                                            notifiable.borrow_mut().new_video_frame(&video_frame);
                                        },
                                        None => (),
                                    };
                                }

                                video_frame = ffmpeg::frame::Video::empty();
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No video decoder"),
                },
                ffmpeg::media::Type::Audio => match self.audio_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let ref mut audio = match self.audio_decoder.as_mut() {
                                Some(decoder) => decoder,
                                None => panic!("Error getting audio decoder for stream {}", stream_index),
                            };
                            if stream_processed.contains(&stream_index) {
                                // stream already processed
                                continue;
                            }
                            match audio.decode(&packet, &mut audio_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = audio_frame.planes();
                                    println!("\tdecoded audio frame, got frame: {}", got_frame);
                                },
                                Err(error) => panic!("Error decoding audio packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                stream_processed.insert(stream_index);
                                for notifiable_weak in self.audio_notifiables.iter() {
                                    match notifiable_weak.upgrade() {
                                        Some(notifiable) => {
                                            notifiable.borrow_mut().new_audio_frame(&audio_frame);
                                        },
                                        None => (),
                                    };
                                }

                                audio_frame = ffmpeg::frame::Audio::empty();
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No audio decoder"),
                },
                _ => (),
            }

            if stream_processed.len() == expected_frames {
                break;
            }
        }
    }
}

fn print_packet_content(stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
    println!("\n* Packet for {:?} stream: {}", stream.disposition(), stream.index());
    println!("\tsize: {} - duration: {}, is key: {}",
             packet.size(), packet.duration(), packet.is_key(),
    );
    match packet.pts() {
        Some(pts) => println!("\tpts: {}", pts),
        None => (),
    }
    match packet.dts() {
        Some(dts) => println!("\tdts: {}", dts),
        None => (),
    }
    if let Some(ref data) = packet.data() {
        println!("\tfound data with len: {}", data.len());
    }
    let side_data_iter = stream.side_data();
    let side_data_len = side_data_iter.size_hint().0;
    if side_data_len > 0 {
        println!("\tside data nb: {}", side_data_len);
    }
}
<|endoftext|>


<commit_before>use winapi::shared::windef::HFONT;
use winapi::um::winnt::HANDLE;
use crate::win32::resources_helper as rh;
use crate::win32::base_helper::{to_utf16, from_utf16};
use crate::NwgError;
use std::ptr;

use std::sync::Mutex;

lazy_static! {
    /// Default font to use when creating controls. Set using `Font::set_global_default` && get using `Font::global_default()`
    static ref DEFAULT_FONT: Mutex<Option<Font>> = {
        Mutex::new(None)
    };
}

pub struct MemFont(pub HANDLE);

/**
Represent a font parameters. Returned by the font dialog when the user selected a font.
Can also be used to create a Font resource using `Font::from_info`
For more information on the parameters see: https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfonta
*/
#[derive(Debug, Clone)]
pub struct FontInfo {
    /// The size of the selected font, in units of 1/10 of a point
    pub point_size: u32,
    /// Specifies the height, in logical units, of the font's character cell or character.
    pub height: i32,
    /// Specifies the width, in logical units, of characters in the font.
    pub width: i32,
    /// Contains the angle, in tenths of degrees, between the escapement vector and the x-axis of the device. The escapement vector is parallel to the base line of a row of text.
    pub escapement: i32,
    /// Specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device.
    pub orientation: i32,
    /// Specifies the weight of the font in the range from 0 through 1000.
    pub weight: i32,
    /// Specifies an italic font if set to TRUE
    pub italic: bool,
    /// Specifies an underlined font if set to TRUE.
    pub underline: bool,
    /// Specifies a strikeout font if set to TRUE.
    pub strike_out: bool,
    /// Specifies the character set.
    pub char_set: u8,
    /// Specifies the output precision. The output precision defines how closely the output must match the requested font's height, width, character orientation, escapement, pitch, and font type.
    pub out_precision: u8,
    /// specifies the clipping precision. The clipping precision defines how to clip characters that are partially outside the clipping region.
    pub clip_precision: u8,
    /// specifies the output quality. The output quality defines how carefully the GDI must attempt to match the logical-font attributes to those of an actual physical font.
    pub quality: u8,
    /// Specifies the pitch and family of the font.
    pub pitch_and_family: u8,
    /// Contains a null-terminated string that specifies the typeface name of the font.
    pub name: String
}

/**

Represent a system font.

Can be used with any controls that draws text. Due to the very limited way win32 can draw text,
only family, size and weight can be configured.

Example:

```rust
use native_windows_gui as nwg;

fn build_font() -> nwg::Font {
    let mut font = nwg::Font::default();

    nwg::Font::builder()
        .size(16)
        .family("Arial")
        .weight(1000)
        .build(&mut font);

    font
}

```

*/
#[derive(PartialEq, Eq, Debug)]
pub struct Font {
    pub handle: HFONT
}

impl Font {

    pub fn builder<'a>() -> FontBuilder<'a> {
        FontBuilder::new()
    }

    /// Set the default (application global!) font that will be used when creating controls and return the old one
    pub fn set_global_default(font: Option<Font>) -> Option<Font> {
        let mut global_font = DEFAULT_FONT.lock().unwrap();
        let old = global_font.take();
        *global_font = font;
        old
    }

    /// Set the default (application global!) font that will be used when creating controls
    /// This is a shortcut over `Font::set_global_default`
    pub fn set_global_family(family: &str) -> Result<Option<Font>, NwgError> {
        let mut font = Font::default();

        Font::builder()
            .family(family)
            .build(&mut font)?;

        Ok(Font::set_global_default(Some(font)))
    }

    /// Return the default font that was previously set using `Font::set_default`
    pub fn global_default() -> Option<Font> {
        DEFAULT_FONT.lock()
            .unwrap()
            .as_ref()
            .map(|f| Font { handle: f.handle } )
    }

    /**
        Add a font to the system font table. Don't forget to call `Font::remove_font(path)` once your done.
        Returns `false` if the font could not be added. Windows won't tell you why though.

        Other info:
        - The value of `path` can be a `ttf` or a `otf` font.
        - Adding the same font multiple time increase the internal refcount
        - Use `Font::families()` to return the available system font families
    */
    pub fn add_font(path: &str) -> bool {
        use winapi::um::wingdi::AddFontResourceW;

        unsafe {
            let path = to_utf16(path);
            AddFontResourceW(path.as_ptr()) > 0
        }
    }

    /// Remove a font that was previously added by `Font::add_font`
    pub fn remove_font(path: &str) {
        use winapi::um::wingdi::RemoveFontResourceW;

        unsafe {
            let path = to_utf16(path);
            RemoveFontResourceW(path.as_ptr());
        }
    }

    /**
        Add a font resource from a binary source. Returns a memory font handle if the font was loaded succesfully.
        Send the handle to `remove_memory_font` at the end of your program to free the font from memory.
    */
    pub fn add_memory_font(bin: &mut [u8]) -> Result<MemFont, ()> {
        use winapi::um::wingdi::AddFontMemResourceEx;

        let bin_len = bin.len();
        let mut num_fonts = 0;
        let handle = unsafe {
            AddFontMemResourceEx(
                bin.as_mut_ptr() as _,
                bin_len as _,
                ptr::null_mut(),
                &mut num_fonts,
            )
        };

        if num_fonts > 0 {
            Ok(MemFont(handle))
        } else {
            Err(())
        }
    }

    /// Remove a font that was previously added by `Font::add_memory_font`
    pub fn remove_memory_font(font: MemFont) {
        use winapi::um::wingdi::RemoveFontMemResourceEx;

        unsafe {
            RemoveFontMemResourceEx(font.0);
        }
    }

    /// Returns all the font families loaded on the OS.
    /// Probably pretty slow, so cache the value if possible
    pub fn families() -> Vec<String> {
        use winapi::um::wingdi::{LOGFONTW, TEXTMETRICW, DEFAULT_CHARSET, EnumFontFamiliesExW};
        use winapi::um::winuser::GetDC;
        use winapi::shared::minwindef::{DWORD, LPARAM};
        use std::mem;

        let mut families = Vec::with_capacity(16);

        unsafe extern "system" fn callback(font_ptr: *const LOGFONTW, _txt: *const TEXTMETRICW, _font_type: DWORD, lparam: LPARAM) -> i32 {
            let families_ptr = lparam as *mut Vec<String>;
            let families = &mut *families_ptr;

            let font = &*font_ptr;
            let family_text = from_utf16(&font.lfFaceName);
            if !families.iter().any(|f| f == &family_text) {
                families.push(family_text);
            }

            1
        }

        unsafe {
            let hdc = GetDC(ptr::null_mut());
            let mut font: LOGFONTW = mem::zeroed();
            font.lfCharSet = DEFAULT_CHARSET as u8;

            EnumFontFamiliesExW(hdc, &mut font, Some(callback), (&mut families as *mut Vec<String>) as _, 0);
        }

        families.shrink_to_fit();
        families
    }

}

impl Default for Font {

    fn default() -> Font {
        Font { handle: ptr::null_mut() }
    }

}

/**
Builds a font struct

Parameters:
    - size: Size of the font. The font mapper transforms this value into device units and matches it against the cell height of the available fonts.
    - size_absolute:  Size of the font. The font mapper transforms this value into device units and matches its absolute value against the character height of the available fonts.
    - weight: Weight of the font. A value betweem 0 and 1000. 0 use the system default, 100 is very thin, 1000 is very bold.
    - family: Family name of the font (ex: Arial). Can be None to use the system default.
*/
pub struct FontBuilder<'a> {
    size: Option<i32>,
    weight: u32,
    family: Option<&'a str>
}

impl<'a> FontBuilder<'a> {

    pub fn new() -> FontBuilder<'a> {
        FontBuilder {
            size: None,
            weight: 0,
            family: None,
        }
    }

    pub fn size(mut self, size: u32) -> FontBuilder<'a> {
        self.size = Some(size as i32);
        self
    }

    pub fn size_absolute(mut self, size: u32) -> FontBuilder<'a> {
        self.size = Some(-(size as i32));
        self
    }

    pub fn weight(mut self, weight: u32) -> FontBuilder<'a> {
        self.weight = weight;
        self
    }

    pub fn family(mut self, fam: &'a str) -> FontBuilder<'a> {
        self.family = Some(fam);
        self
    }

    pub fn build(self, font: &mut Font) -> Result<(), NwgError> {

        font.handle = unsafe { rh::build_font(
            self.size.unwrap_or(0),
            self.weight,
            [false, false, false],
            self.family
        ) }?;

        Ok(())
    }

}

unsafe impl Send for Font {}
unsafe impl Sync for Font {}

unsafe impl Send for MemFont {}
unsafe impl Sync for MemFont {}
<commit_msg>fix typo in font.rs<commit_after>use winapi::shared::windef::HFONT;
use winapi::um::winnt::HANDLE;
use crate::win32::resources_helper as rh;
use crate::win32::base_helper::{to_utf16, from_utf16};
use crate::NwgError;
use std::ptr;

use std::sync::Mutex;

lazy_static! {
    /// Default font to use when creating controls. Set using `Font::set_global_default` && get using `Font::global_default()`
    static ref DEFAULT_FONT: Mutex<Option<Font>> = {
        Mutex::new(None)
    };
}

pub struct MemFont(pub HANDLE);

/**
Represent a font parameters. Returned by the font dialog when the user selected a font.
Can also be used to create a Font resource using `Font::from_info`
For more information on the parameters see: https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logfonta
*/
#[derive(Debug, Clone)]
pub struct FontInfo {
    /// The size of the selected font, in units of 1/10 of a point
    pub point_size: u32,
    /// Specifies the height, in logical units, of the font's character cell or character.
    pub height: i32,
    /// Specifies the width, in logical units, of characters in the font.
    pub width: i32,
    /// Contains the angle, in tenths of degrees, between the escapement vector and the x-axis of the device. The escapement vector is parallel to the base line of a row of text.
    pub escapement: i32,
    /// Specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device.
    pub orientation: i32,
    /// Specifies the weight of the font in the range from 0 through 1000.
    pub weight: i32,
    /// Specifies an italic font if set to TRUE
    pub italic: bool,
    /// Specifies an underlined font if set to TRUE.
    pub underline: bool,
    /// Specifies a strikeout font if set to TRUE.
    pub strike_out: bool,
    /// Specifies the character set.
    pub char_set: u8,
    /// Specifies the output precision. The output precision defines how closely the output must match the requested font's height, width, character orientation, escapement, pitch, and font type.
    pub out_precision: u8,
    /// specifies the clipping precision. The clipping precision defines how to clip characters that are partially outside the clipping region.
    pub clip_precision: u8,
    /// specifies the output quality. The output quality defines how carefully the GDI must attempt to match the logical-font attributes to those of an actual physical font.
    pub quality: u8,
    /// Specifies the pitch and family of the font.
    pub pitch_and_family: u8,
    /// Contains a null-terminated string that specifies the typeface name of the font.
    pub name: String
}

/**

Represent a system font.

Can be used with any controls that draws text. Due to the very limited way win32 can draw text,
only family, size and weight can be configured.

Example:

```rust
use native_windows_gui as nwg;

fn build_font() -> nwg::Font {
    let mut font = nwg::Font::default();

    nwg::Font::builder()
        .size(16)
        .family("Arial")
        .weight(1000)
        .build(&mut font);

    font
}

```

*/
#[derive(PartialEq, Eq, Debug)]
pub struct Font {
    pub handle: HFONT
}

impl Font {

    pub fn builder<'a>() -> FontBuilder<'a> {
        FontBuilder::new()
    }

    /// Set the default (application global!) font that will be used when creating controls and return the old one
    pub fn set_global_default(font: Option<Font>) -> Option<Font> {
        let mut global_font = DEFAULT_FONT.lock().unwrap();
        let old = global_font.take();
        *global_font = font;
        old
    }

    /// Set the default (application global!) font that will be used when creating controls
    /// This is a shortcut over `Font::set_global_default`
    pub fn set_global_family(family: &str) -> Result<Option<Font>, NwgError> {
        let mut font = Font::default();

        Font::builder()
            .family(family)
            .build(&mut font)?;

        Ok(Font::set_global_default(Some(font)))
    }

    /// Return the default font that was previously set using `Font::set_default`
    pub fn global_default() -> Option<Font> {
        DEFAULT_FONT.lock()
            .unwrap()
            .as_ref()
            .map(|f| Font { handle: f.handle } )
    }

    /**
        Add a font to the system font table. Don't forget to call `Font::remove_font(path)` once you're done.
        Returns `false` if the font could not be added. Windows won't tell you why though.

        Other info:
        - The value of `path` can be a `ttf` or a `otf` font.
        - Adding the same font multiple time increase the internal refcount
        - Use `Font::families()` to return the available system font families
    */
    pub fn add_font(path: &str) -> bool {
        use winapi::um::wingdi::AddFontResourceW;

        unsafe {
            let path = to_utf16(path);
            AddFontResourceW(path.as_ptr()) > 0
        }
    }

    /// Remove a font that was previously added by `Font::add_font`
    pub fn remove_font(path: &str) {
        use winapi::um::wingdi::RemoveFontResourceW;

        unsafe {
            let path = to_utf16(path);
            RemoveFontResourceW(path.as_ptr());
        }
    }

    /**
        Add a font resource from a binary source. Returns a memory font handle if the font was loaded succesfully.
        Send the handle to `remove_memory_font` at the end of your program to free the font from memory.
    */
    pub fn add_memory_font(bin: &mut [u8]) -> Result<MemFont, ()> {
        use winapi::um::wingdi::AddFontMemResourceEx;

        let bin_len = bin.len();
        let mut num_fonts = 0;
        let handle = unsafe {
            AddFontMemResourceEx(
                bin.as_mut_ptr() as _,
                bin_len as _,
                ptr::null_mut(),
                &mut num_fonts,
            )
        };

        if num_fonts > 0 {
            Ok(MemFont(handle))
        } else {
            Err(())
        }
    }

    /// Remove a font that was previously added by `Font::add_memory_font`
    pub fn remove_memory_font(font: MemFont) {
        use winapi::um::wingdi::RemoveFontMemResourceEx;

        unsafe {
            RemoveFontMemResourceEx(font.0);
        }
    }

    /// Returns all the font families loaded on the OS.
    /// Probably pretty slow, so cache the value if possible
    pub fn families() -> Vec<String> {
        use winapi::um::wingdi::{LOGFONTW, TEXTMETRICW, DEFAULT_CHARSET, EnumFontFamiliesExW};
        use winapi::um::winuser::GetDC;
        use winapi::shared::minwindef::{DWORD, LPARAM};
        use std::mem;

        let mut families = Vec::with_capacity(16);

        unsafe extern "system" fn callback(font_ptr: *const LOGFONTW, _txt: *const TEXTMETRICW, _font_type: DWORD, lparam: LPARAM) -> i32 {
            let families_ptr = lparam as *mut Vec<String>;
            let families = &mut *families_ptr;

            let font = &*font_ptr;
            let family_text = from_utf16(&font.lfFaceName);
            if !families.iter().any(|f| f == &family_text) {
                families.push(family_text);
            }

            1
        }

        unsafe {
            let hdc = GetDC(ptr::null_mut());
            let mut font: LOGFONTW = mem::zeroed();
            font.lfCharSet = DEFAULT_CHARSET as u8;

            EnumFontFamiliesExW(hdc, &mut font, Some(callback), (&mut families as *mut Vec<String>) as _, 0);
        }

        families.shrink_to_fit();
        families
    }

}

impl Default for Font {

    fn default() -> Font {
        Font { handle: ptr::null_mut() }
    }

}

/**
Builds a font struct

Parameters:
    - size: Size of the font. The font mapper transforms this value into device units and matches it against the cell height of the available fonts.
    - size_absolute:  Size of the font. The font mapper transforms this value into device units and matches its absolute value against the character height of the available fonts.
    - weight: Weight of the font. A value betweem 0 and 1000. 0 use the system default, 100 is very thin, 1000 is very bold.
    - family: Family name of the font (ex: Arial). Can be None to use the system default.
*/
pub struct FontBuilder<'a> {
    size: Option<i32>,
    weight: u32,
    family: Option<&'a str>
}

impl<'a> FontBuilder<'a> {

    pub fn new() -> FontBuilder<'a> {
        FontBuilder {
            size: None,
            weight: 0,
            family: None,
        }
    }

    pub fn size(mut self, size: u32) -> FontBuilder<'a> {
        self.size = Some(size as i32);
        self
    }

    pub fn size_absolute(mut self, size: u32) -> FontBuilder<'a> {
        self.size = Some(-(size as i32));
        self
    }

    pub fn weight(mut self, weight: u32) -> FontBuilder<'a> {
        self.weight = weight;
        self
    }

    pub fn family(mut self, fam: &'a str) -> FontBuilder<'a> {
        self.family = Some(fam);
        self
    }

    pub fn build(self, font: &mut Font) -> Result<(), NwgError> {

        font.handle = unsafe { rh::build_font(
            self.size.unwrap_or(0),
            self.weight,
            [false, false, false],
            self.family
        ) }?;

        Ok(())
    }

}

unsafe impl Send for Font {}
unsafe impl Sync for Font {}

unsafe impl Send for MemFont {}
unsafe impl Sync for MemFont {}
<|endoftext|>


<commit_before>use std::fmt::{Debug, Formatter};
use std::fmt;
use std::ops::Deref;

use clap::ArgMatches;

use runtime::Runtime;
use module::Module;

use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
use module::helpers::cli::create_tag_filter;
use module::helpers::cli::create_hash_filter;
use module::helpers::cli::create_text_header_field_grep_filter;
use module::helpers::cli::create_content_grep_filter;
use module::helpers::cli::CliFileFilter;

mod header;

use self::header::get_url_from_header;
use self::header::get_tags_from_header;

pub struct BM<'a> {
    rt: &'a Runtime<'a>,
}

impl<'a> BM<'a> {

    pub fn new(rt: &'a Runtime<'a>) -> BM<'a> {
        BM {
            rt: rt,
        }
    }

    /**
     * Subcommand: add
     */
    fn command_add(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};
        use std::process::exit;
        use self::header::build_header;

        let parser = Parser::new(JsonHeaderParser::new(None));

        let url    = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present

        if !self.validate_url(&url, &parser) {
            error!("URL validation failed, exiting.");
            exit(1);
        } else {
            debug!("Verification succeeded");
        }

        let tags   = matches.value_of("tags").and_then(|s| {
            Some(s.split(",").map(String::from).collect())
        }).unwrap_or(vec![]);

        debug!("Building header with");
        debug!("    url  = '{:?}'", url);
        debug!("    tags = '{:?}'", tags);
        let header = build_header(url, tags);

        let fileid = self.rt
                         .store()
                         .new_file_with_header(self, header);

        let result = self.rt
            .store()
            .load(self, &parser, &fileid)
            .map(|file| {
                info!("{}", Yellow.paint(format!("Created file in memory: {}", fileid)));
                self.rt
                    .store()
                    .persist(&parser, file)
            })
            .unwrap_or(false);

        if result {
            info!("{}", Red.paint("Adding worked"));
        } else {
            info!("{}", Green.paint("Adding failed"));
        }

        result
    }

    fn validate_url<HP>(&self, url: &String, parser: &Parser<HP>) -> bool
        where HP: FileHeaderParser
    {
        use util::is_url;

        if !is_url(url) {
            error!("Url '{}' is not a valid URL. Will not store.", url);
            return false;
        }

        let is_in_store = self.rt
            .store()
            .load_for_module(self, parser)
            .iter()
            .any(|file| {
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url_in_store| {
                    &url_in_store == url
                }).unwrap_or(false)
            });

        if is_in_store {
            error!("URL '{}' seems to be in the store already", url);
            return false;
        }

        return true;
    }

    /**
     * Subcommand: list
     */
    fn command_list(&self, matches: &ArgMatches) -> bool {
        use ui::file::{FilePrinter, TablePrinter};
        use std::ops::Deref;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter = {
            let hash_filter = create_hash_filter(matches, "id", true);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", true);
            let tags_filter = create_tag_filter(matches, "tags", true);
            hash_filter.and(Box::new(text_filter)).and(Box::new(tags_filter))
        };

        let files  = self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file));
        let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());

        printer.print_files_custom(files,
            &|file| {
                let fl = file.deref().borrow();
                let hdr = fl.header();
                let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
                let tags = get_tags_from_header(hdr);

                debug!("Custom printer field: url  = '{:?}'", url);
                debug!("Custom printer field: tags = '{:?}'", tags);

                vec![url, tags.join(", ")]
            }
        );
        true
    }

    /**
     * Subcommand: open
     */
    fn command_open(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};
        use open;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = {
            let hash_filter = create_hash_filter(matches, "id", true);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", true);
            let tags_filter = create_tag_filter(matches, "tags", true);
            Box::new(hash_filter.and(Box::new(text_filter)).and(Box::new(tags_filter)))
        };
        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can open now: {:?}", file);
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url| {
                    if open::that(&url[..]).is_ok() {
                        info!("{}", Green.paint(format!("open({})", url)));
                        true
                    } else {
                        info!("{}", Red.paint(format!("could not open({})", url)));
                        false
                    }
                })
                .unwrap_or(false)
            })
            .fold((0, 0), |acc, succeeded| {
                let (worked, failed) = acc;
                if succeeded {
                    (worked + 1, failed)
                } else {
                    (worked, failed + 1)
                }
            });

        let (succ, fail) = result;
        info!("{}", Green.paint(format!("open() succeeded for {} files", succ)));
        info!("{}", Red.paint(format!(  "open() failed    for {} files", fail)));
        return fail == 0;
    }

    /**
     * Subcommand: remove
     */
    fn command_remove(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};

        let parser = Parser::new(JsonHeaderParser::new(None));

        let filter = {
            let hash_filter = create_hash_filter(matches, "id", false);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", false);
            let tags_filter = create_tag_filter(matches, "tags", false);
            hash_filter.or(Box::new(text_filter)).or(Box::new(tags_filter))
        };

        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can remove now: {:?}", file);
                let f = file.deref().borrow();
                self.rt.store().remove(f.id().clone())
            })
            .fold((0, 0), |acc, succeeded| {
                let (worked, failed) = acc;
                if succeeded {
                    (worked + 1, failed)
                } else {
                    (worked, failed + 1)
                }
            });

        let (worked, failed) = result;

        info!("{}", Green.paint(format!("Removing succeeded for {} files", worked)));
        info!("{}", Red.paint(format!(  "Removing failed for {} files", failed)));

        return failed == 0;
    }

    /**
     * Subcommand: add_tags
     */
    fn command_add_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            let mut new_tags = old_tags.clone();
            new_tags.append(&mut cli_tags.clone());
            new_tags
        }, rebuild_header_with_tags)
    }

    /**
     * Subcommand: rm_tags
     */
    fn command_rm_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            old_tags.clone()
                .into_iter()
                .filter(|tag| !cli_tags.contains(tag))
                .collect()
        }, rebuild_header_with_tags)
    }

    /**
     * Subcommand: set_tags
     */
    fn command_set_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            cli_tags.clone()
        }, rebuild_header_with_tags)
    }

}

/**
 * Trait implementation for BM module
 */
impl<'a> Module<'a> for BM<'a> {

    fn exec(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};

        match matches.subcommand_name() {
            Some("add") => {
                self.command_add(matches.subcommand_matches("add").unwrap())
            },

            Some("list") => {
                self.command_list(matches.subcommand_matches("list").unwrap())
            },

            Some("open") => {
                self.command_open(matches.subcommand_matches("open").unwrap())
            },

            Some("remove") => {
                self.command_remove(matches.subcommand_matches("remove").unwrap())
            },

            Some("add_tags") => {
                self.command_add_tags(matches.subcommand_matches("add_tags").unwrap())
            },

            Some("rm_tags") => {
                self.command_rm_tags(matches.subcommand_matches("rm_tags").unwrap())
            },

            Some("set_tags") => {
                self.command_set_tags(matches.subcommand_matches("set_tags").unwrap())
            },

            Some(_) | None => {
                info!("{}", Red.bold().paint("No command given, doing nothing"));
                false
            },
        }
    }

    fn name(&self) -> &'static str {
        "bookmark"
    }

    fn runtime(&self) -> &Runtime {
        self.rt
    }
}

impl<'a> Debug for BM<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "BM"));
        Ok(())
    }

}

<commit_msg>Remove unused import<commit_after>use std::fmt::{Debug, Formatter};
use std::fmt;
use std::ops::Deref;

use clap::ArgMatches;

use runtime::Runtime;
use module::Module;

use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
use module::helpers::cli::create_tag_filter;
use module::helpers::cli::create_hash_filter;
use module::helpers::cli::create_text_header_field_grep_filter;
use module::helpers::cli::CliFileFilter;

mod header;

use self::header::get_url_from_header;
use self::header::get_tags_from_header;

pub struct BM<'a> {
    rt: &'a Runtime<'a>,
}

impl<'a> BM<'a> {

    pub fn new(rt: &'a Runtime<'a>) -> BM<'a> {
        BM {
            rt: rt,
        }
    }

    /**
     * Subcommand: add
     */
    fn command_add(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};
        use std::process::exit;
        use self::header::build_header;

        let parser = Parser::new(JsonHeaderParser::new(None));

        let url    = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present

        if !self.validate_url(&url, &parser) {
            error!("URL validation failed, exiting.");
            exit(1);
        } else {
            debug!("Verification succeeded");
        }

        let tags   = matches.value_of("tags").and_then(|s| {
            Some(s.split(",").map(String::from).collect())
        }).unwrap_or(vec![]);

        debug!("Building header with");
        debug!("    url  = '{:?}'", url);
        debug!("    tags = '{:?}'", tags);
        let header = build_header(url, tags);

        let fileid = self.rt
                         .store()
                         .new_file_with_header(self, header);

        let result = self.rt
            .store()
            .load(self, &parser, &fileid)
            .map(|file| {
                info!("{}", Yellow.paint(format!("Created file in memory: {}", fileid)));
                self.rt
                    .store()
                    .persist(&parser, file)
            })
            .unwrap_or(false);

        if result {
            info!("{}", Red.paint("Adding worked"));
        } else {
            info!("{}", Green.paint("Adding failed"));
        }

        result
    }

    fn validate_url<HP>(&self, url: &String, parser: &Parser<HP>) -> bool
        where HP: FileHeaderParser
    {
        use util::is_url;

        if !is_url(url) {
            error!("Url '{}' is not a valid URL. Will not store.", url);
            return false;
        }

        let is_in_store = self.rt
            .store()
            .load_for_module(self, parser)
            .iter()
            .any(|file| {
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url_in_store| {
                    &url_in_store == url
                }).unwrap_or(false)
            });

        if is_in_store {
            error!("URL '{}' seems to be in the store already", url);
            return false;
        }

        return true;
    }

    /**
     * Subcommand: list
     */
    fn command_list(&self, matches: &ArgMatches) -> bool {
        use ui::file::{FilePrinter, TablePrinter};
        use std::ops::Deref;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter = {
            let hash_filter = create_hash_filter(matches, "id", true);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", true);
            let tags_filter = create_tag_filter(matches, "tags", true);
            hash_filter.and(Box::new(text_filter)).and(Box::new(tags_filter))
        };

        let files  = self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file));
        let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());

        printer.print_files_custom(files,
            &|file| {
                let fl = file.deref().borrow();
                let hdr = fl.header();
                let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
                let tags = get_tags_from_header(hdr);

                debug!("Custom printer field: url  = '{:?}'", url);
                debug!("Custom printer field: tags = '{:?}'", tags);

                vec![url, tags.join(", ")]
            }
        );
        true
    }

    /**
     * Subcommand: open
     */
    fn command_open(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};
        use open;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = {
            let hash_filter = create_hash_filter(matches, "id", true);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", true);
            let tags_filter = create_tag_filter(matches, "tags", true);
            Box::new(hash_filter.and(Box::new(text_filter)).and(Box::new(tags_filter)))
        };
        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can open now: {:?}", file);
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url| {
                    if open::that(&url[..]).is_ok() {
                        info!("{}", Green.paint(format!("open({})", url)));
                        true
                    } else {
                        info!("{}", Red.paint(format!("could not open({})", url)));
                        false
                    }
                })
                .unwrap_or(false)
            })
            .fold((0, 0), |acc, succeeded| {
                let (worked, failed) = acc;
                if succeeded {
                    (worked + 1, failed)
                } else {
                    (worked, failed + 1)
                }
            });

        let (succ, fail) = result;
        info!("{}", Green.paint(format!("open() succeeded for {} files", succ)));
        info!("{}", Red.paint(format!(  "open() failed    for {} files", fail)));
        return fail == 0;
    }

    /**
     * Subcommand: remove
     */
    fn command_remove(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};

        let parser = Parser::new(JsonHeaderParser::new(None));

        let filter = {
            let hash_filter = create_hash_filter(matches, "id", false);
            let text_filter = create_text_header_field_grep_filter(matches, "match", "URL", false);
            let tags_filter = create_tag_filter(matches, "tags", false);
            hash_filter.or(Box::new(text_filter)).or(Box::new(tags_filter))
        };

        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can remove now: {:?}", file);
                let f = file.deref().borrow();
                self.rt.store().remove(f.id().clone())
            })
            .fold((0, 0), |acc, succeeded| {
                let (worked, failed) = acc;
                if succeeded {
                    (worked + 1, failed)
                } else {
                    (worked, failed + 1)
                }
            });

        let (worked, failed) = result;

        info!("{}", Green.paint(format!("Removing succeeded for {} files", worked)));
        info!("{}", Red.paint(format!(  "Removing failed for {} files", failed)));

        return failed == 0;
    }

    /**
     * Subcommand: add_tags
     */
    fn command_add_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            let mut new_tags = old_tags.clone();
            new_tags.append(&mut cli_tags.clone());
            new_tags
        }, rebuild_header_with_tags)
    }

    /**
     * Subcommand: rm_tags
     */
    fn command_rm_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            old_tags.clone()
                .into_iter()
                .filter(|tag| !cli_tags.contains(tag))
                .collect()
        }, rebuild_header_with_tags)
    }

    /**
     * Subcommand: set_tags
     */
    fn command_set_tags(&self, matches: &ArgMatches) -> bool {
        use module::helpers::header::tags::data::alter_tags_in_files;
        use self::header::rebuild_header_with_tags;

        let parser = Parser::new(JsonHeaderParser::new(None));
        alter_tags_in_files(self, matches, &parser, |old_tags, cli_tags| {
            cli_tags.clone()
        }, rebuild_header_with_tags)
    }

}

/**
 * Trait implementation for BM module
 */
impl<'a> Module<'a> for BM<'a> {

    fn exec(&self, matches: &ArgMatches) -> bool {
        use ansi_term::Colour::{Green, Yellow, Red};

        match matches.subcommand_name() {
            Some("add") => {
                self.command_add(matches.subcommand_matches("add").unwrap())
            },

            Some("list") => {
                self.command_list(matches.subcommand_matches("list").unwrap())
            },

            Some("open") => {
                self.command_open(matches.subcommand_matches("open").unwrap())
            },

            Some("remove") => {
                self.command_remove(matches.subcommand_matches("remove").unwrap())
            },

            Some("add_tags") => {
                self.command_add_tags(matches.subcommand_matches("add_tags").unwrap())
            },

            Some("rm_tags") => {
                self.command_rm_tags(matches.subcommand_matches("rm_tags").unwrap())
            },

            Some("set_tags") => {
                self.command_set_tags(matches.subcommand_matches("set_tags").unwrap())
            },

            Some(_) | None => {
                info!("{}", Red.bold().paint("No command given, doing nothing"));
                false
            },
        }
    }

    fn name(&self) -> &'static str {
        "bookmark"
    }

    fn runtime(&self) -> &Runtime {
        self.rt
    }
}

impl<'a> Debug for BM<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "BM"));
        Ok(())
    }

}

<|endoftext|>


<commit_before>fn sum_vec(nums: &Vec<i32>) -> i32 {
    let mut result = 0;
    for i in nums {
        result += *i;
    }
    result
}

fn check_sub_array_sum(nums: Vec<i32>, k: i32) -> bool {
    let length = nums.len();
    if length <= 1 {
        return false;
    }

    if sum_vec(&nums) == 0 {
        return true;
    }

    if k == 0 {
        return false;
    }

    if length >= 2 && k > 0 {
        return true;
    }
}

fn main() {}
<commit_msg>not finish<commit_after>fn sum_vec(nums: &Vec<i32>) -> i32 {
    let mut result = 0;
    for i in nums {
        result += *i;
    }
    result
}

fn check_sub_array_sum(nums: Vec<i32>, k: i32) -> bool {
    let length = nums.len();
    if length <= 1 {
        return false;
    }

    if sum_vec(&nums) == 0 {
        return true;
    }

    if k == 0 {
        return false;
    }

    if length >= 2 && k > 0 {
        return true;
    }

    let inner_k = k.abs();
    //not finish
}

fn main() {}
<|endoftext|>


<commit_before>use crate::stream::Stream;

use bytes::{Buf, BufMut, Bytes, BytesMut};
use core::future::Future;
use core::mem;
use core::pin::Pin;
use core::task::{Context, Poll};
use pin_project_lite::pin_project;

// Do not export this struct until `FromStream` can be unsealed.
pin_project! {
    /// Future returned by the [`collect`](super::StreamExt::collect) method.
    #[must_use = "streams do nothing unless polled"]
    #[derive(Debug)]
    pub struct Collect<T, U>
    where
        T: Stream,
        U: FromStream<T::Item>,
    {
        #[pin]
        stream: T,
        collection: U::Collection,
    }
}

/// Convert from a [`Stream`](crate::stream::Stream).
///
/// This trait is not intended to be used directly. Instead, call
/// [`StreamExt::collect()`](super::StreamExt::collect).
///
/// # Implementing
///
/// Currently, this trait may not be implemented by third parties. The trait is
/// sealed in order to make changes in the future. Stabilization is pending
/// enhancements to the Rust language.
pub trait FromStream<T>: sealed::FromStreamPriv<T> {}

impl<T, U> Collect<T, U>
where
    T: Stream,
    U: FromStream<T::Item>,
{
    pub(super) fn new(stream: T) -> Collect<T, U> {
        let (lower, upper) = stream.size_hint();
        let collection = U::initialize(lower, upper);

        Collect { stream, collection }
    }
}

impl<T, U> Future for Collect<T, U>
where
    T: Stream,
    U: FromStream<T::Item>,
{
    type Output = U;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<U> {
        use Poll::Ready;

        loop {
            let mut me = self.as_mut().project();

            let item = match ready!(me.stream.poll_next(cx)) {
                Some(item) => item,
                None => {
                    return Ready(U::finalize(&mut me.collection));
                }
            };

            if !U::extend(&mut me.collection, item) {
                return Ready(U::finalize(&mut me.collection));
            }
        }
    }
}

// ===== FromStream implementations

impl FromStream<()> for () {}

impl sealed::FromStreamPriv<()> for () {
    type Collection = ();

    fn initialize(_lower: usize, _upper: Option<usize>) {}

    fn extend(_collection: &mut (), _item: ()) -> bool {
        true
    }

    fn finalize(_collection: &mut ()) {}
}

impl<T: AsRef<str>> FromStream<T> for String {}

impl<T: AsRef<str>> sealed::FromStreamPriv<T> for String {
    type Collection = String;

    fn initialize(_lower: usize, _upper: Option<usize>) -> String {
        String::new()
    }

    fn extend(collection: &mut String, item: T) -> bool {
        collection.push_str(item.as_ref());
        true
    }

    fn finalize(collection: &mut String) -> String {
        mem::replace(collection, String::new())
    }
}

impl<T> FromStream<T> for Vec<T> {}

impl<T> sealed::FromStreamPriv<T> for Vec<T> {
    type Collection = Vec<T>;

    fn initialize(lower: usize, _upper: Option<usize>) -> Vec<T> {
        Vec::with_capacity(lower)
    }

    fn extend(collection: &mut Vec<T>, item: T) -> bool {
        collection.push(item);
        true
    }

    fn finalize(collection: &mut Vec<T>) -> Vec<T> {
        mem::replace(collection, vec![])
    }
}

impl<T> FromStream<T> for Box<[T]> {}

impl<T> sealed::FromStreamPriv<T> for Box<[T]> {
    type Collection = Vec<T>;

    fn initialize(lower: usize, upper: Option<usize>) -> Vec<T> {
        <Vec<T> as sealed::FromStreamPriv<T>>::initialize(lower, upper)
    }

    fn extend(collection: &mut Vec<T>, item: T) -> bool {
        <Vec<T> as sealed::FromStreamPriv<T>>::extend(collection, item)
    }

    fn finalize(collection: &mut Vec<T>) -> Box<[T]> {
        <Vec<T> as sealed::FromStreamPriv<T>>::finalize(collection).into_boxed_slice()
    }
}

impl<T, U, E> FromStream<Result<T, E>> for Result<U, E> where U: FromStream<T> {}

impl<T, U, E> sealed::FromStreamPriv<Result<T, E>> for Result<U, E>
where
    U: FromStream<T>,
{
    type Collection = Result<U::Collection, E>;

    fn initialize(lower: usize, upper: Option<usize>) -> Result<U::Collection, E> {
        Ok(U::initialize(lower, upper))
    }

    fn extend(collection: &mut Self::Collection, item: Result<T, E>) -> bool {
        assert!(collection.is_ok());
        match item {
            Ok(item) => {
                let collection = collection.as_mut().ok().expect("invalid state");
                U::extend(collection, item)
            }
            Err(err) => {
                *collection = Err(err);
                false
            }
        }
    }

    fn finalize(collection: &mut Self::Collection) -> Result<U, E> {
        if let Ok(collection) = collection.as_mut() {
            Ok(U::finalize(collection))
        } else {
            let res = mem::replace(collection, Ok(U::initialize(0, Some(0))));

            if let Err(err) = res {
                Err(err)
            } else {
                unreachable!();
            }
        }
    }
}

impl<T: Buf> FromStream<T> for Bytes {}

impl<T: Buf> sealed::FromStreamPriv<T> for Bytes {
    type Collection = BytesMut;

    fn initialize(_lower: usize, _upper: Option<usize>) -> BytesMut {
        BytesMut::new()
    }

    fn extend(collection: &mut BytesMut, item: T) -> bool {
        collection.put(item);
        true
    }

    fn finalize(collection: &mut BytesMut) -> Bytes {
        mem::replace(collection, BytesMut::new()).freeze()
    }
}

impl<T: Buf> FromStream<T> for BytesMut {}

impl<T: Buf> sealed::FromStreamPriv<T> for BytesMut {
    type Collection = BytesMut;

    fn initialize(_lower: usize, _upper: Option<usize>) -> BytesMut {
        BytesMut::new()
    }

    fn extend(collection: &mut BytesMut, item: T) -> bool {
        collection.put(item);
        true
    }

    fn finalize(collection: &mut BytesMut) -> BytesMut {
        mem::replace(collection, BytesMut::new())
    }
}

pub(crate) mod sealed {
    #[doc(hidden)]
    pub trait FromStreamPriv<T> {
        /// Intermediate type used during collection process
        type Collection;

        /// Initialize the collection
        fn initialize(lower: usize, upper: Option<usize>) -> Self::Collection;

        /// Extend the collection with the received item
        ///
        /// Return `true` to continue streaming, `false` complete collection.
        fn extend(collection: &mut Self::Collection, item: T) -> bool;

        /// Finalize collection into target type.
        fn finalize(collection: &mut Self::Collection) -> Self;
    }
}
<commit_msg>Seal FromStream methods with an internal argument (#2894)<commit_after>use crate::stream::Stream;

use bytes::{Buf, BufMut, Bytes, BytesMut};
use core::future::Future;
use core::mem;
use core::pin::Pin;
use core::task::{Context, Poll};
use pin_project_lite::pin_project;

// Do not export this struct until `FromStream` can be unsealed.
pin_project! {
    /// Future returned by the [`collect`](super::StreamExt::collect) method.
    #[must_use = "streams do nothing unless polled"]
    #[derive(Debug)]
    pub struct Collect<T, U>
    where
        T: Stream,
        U: FromStream<T::Item>,
    {
        #[pin]
        stream: T,
        collection: U::InternalCollection,
    }
}

/// Convert from a [`Stream`](crate::stream::Stream).
///
/// This trait is not intended to be used directly. Instead, call
/// [`StreamExt::collect()`](super::StreamExt::collect).
///
/// # Implementing
///
/// Currently, this trait may not be implemented by third parties. The trait is
/// sealed in order to make changes in the future. Stabilization is pending
/// enhancements to the Rust language.
pub trait FromStream<T>: sealed::FromStreamPriv<T> {}

impl<T, U> Collect<T, U>
where
    T: Stream,
    U: FromStream<T::Item>,
{
    pub(super) fn new(stream: T) -> Collect<T, U> {
        let (lower, upper) = stream.size_hint();
        let collection = U::initialize(sealed::Internal, lower, upper);

        Collect { stream, collection }
    }
}

impl<T, U> Future for Collect<T, U>
where
    T: Stream,
    U: FromStream<T::Item>,
{
    type Output = U;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<U> {
        use Poll::Ready;

        loop {
            let mut me = self.as_mut().project();

            let item = match ready!(me.stream.poll_next(cx)) {
                Some(item) => item,
                None => {
                    return Ready(U::finalize(sealed::Internal, &mut me.collection));
                }
            };

            if !U::extend(sealed::Internal, &mut me.collection, item) {
                return Ready(U::finalize(sealed::Internal, &mut me.collection));
            }
        }
    }
}

// ===== FromStream implementations

impl FromStream<()> for () {}

impl sealed::FromStreamPriv<()> for () {
    type InternalCollection = ();

    fn initialize(_: sealed::Internal, _lower: usize, _upper: Option<usize>) {}

    fn extend(_: sealed::Internal, _collection: &mut (), _item: ()) -> bool {
        true
    }

    fn finalize(_: sealed::Internal, _collection: &mut ()) {}
}

impl<T: AsRef<str>> FromStream<T> for String {}

impl<T: AsRef<str>> sealed::FromStreamPriv<T> for String {
    type InternalCollection = String;

    fn initialize(_: sealed::Internal, _lower: usize, _upper: Option<usize>) -> String {
        String::new()
    }

    fn extend(_: sealed::Internal, collection: &mut String, item: T) -> bool {
        collection.push_str(item.as_ref());
        true
    }

    fn finalize(_: sealed::Internal, collection: &mut String) -> String {
        mem::replace(collection, String::new())
    }
}

impl<T> FromStream<T> for Vec<T> {}

impl<T> sealed::FromStreamPriv<T> for Vec<T> {
    type InternalCollection = Vec<T>;

    fn initialize(_: sealed::Internal, lower: usize, _upper: Option<usize>) -> Vec<T> {
        Vec::with_capacity(lower)
    }

    fn extend(_: sealed::Internal, collection: &mut Vec<T>, item: T) -> bool {
        collection.push(item);
        true
    }

    fn finalize(_: sealed::Internal, collection: &mut Vec<T>) -> Vec<T> {
        mem::replace(collection, vec![])
    }
}

impl<T> FromStream<T> for Box<[T]> {}

impl<T> sealed::FromStreamPriv<T> for Box<[T]> {
    type InternalCollection = Vec<T>;

    fn initialize(_: sealed::Internal, lower: usize, upper: Option<usize>) -> Vec<T> {
        <Vec<T> as sealed::FromStreamPriv<T>>::initialize(sealed::Internal, lower, upper)
    }

    fn extend(_: sealed::Internal, collection: &mut Vec<T>, item: T) -> bool {
        <Vec<T> as sealed::FromStreamPriv<T>>::extend(sealed::Internal, collection, item)
    }

    fn finalize(_: sealed::Internal, collection: &mut Vec<T>) -> Box<[T]> {
        <Vec<T> as sealed::FromStreamPriv<T>>::finalize(sealed::Internal, collection)
            .into_boxed_slice()
    }
}

impl<T, U, E> FromStream<Result<T, E>> for Result<U, E> where U: FromStream<T> {}

impl<T, U, E> sealed::FromStreamPriv<Result<T, E>> for Result<U, E>
where
    U: FromStream<T>,
{
    type InternalCollection = Result<U::InternalCollection, E>;

    fn initialize(
        _: sealed::Internal,
        lower: usize,
        upper: Option<usize>,
    ) -> Result<U::InternalCollection, E> {
        Ok(U::initialize(sealed::Internal, lower, upper))
    }

    fn extend(
        _: sealed::Internal,
        collection: &mut Self::InternalCollection,
        item: Result<T, E>,
    ) -> bool {
        assert!(collection.is_ok());
        match item {
            Ok(item) => {
                let collection = collection.as_mut().ok().expect("invalid state");
                U::extend(sealed::Internal, collection, item)
            }
            Err(err) => {
                *collection = Err(err);
                false
            }
        }
    }

    fn finalize(_: sealed::Internal, collection: &mut Self::InternalCollection) -> Result<U, E> {
        if let Ok(collection) = collection.as_mut() {
            Ok(U::finalize(sealed::Internal, collection))
        } else {
            let res = mem::replace(collection, Ok(U::initialize(sealed::Internal, 0, Some(0))));

            if let Err(err) = res {
                Err(err)
            } else {
                unreachable!();
            }
        }
    }
}

impl<T: Buf> FromStream<T> for Bytes {}

impl<T: Buf> sealed::FromStreamPriv<T> for Bytes {
    type InternalCollection = BytesMut;

    fn initialize(_: sealed::Internal, _lower: usize, _upper: Option<usize>) -> BytesMut {
        BytesMut::new()
    }

    fn extend(_: sealed::Internal, collection: &mut BytesMut, item: T) -> bool {
        collection.put(item);
        true
    }

    fn finalize(_: sealed::Internal, collection: &mut BytesMut) -> Bytes {
        mem::replace(collection, BytesMut::new()).freeze()
    }
}

impl<T: Buf> FromStream<T> for BytesMut {}

impl<T: Buf> sealed::FromStreamPriv<T> for BytesMut {
    type InternalCollection = BytesMut;

    fn initialize(_: sealed::Internal, _lower: usize, _upper: Option<usize>) -> BytesMut {
        BytesMut::new()
    }

    fn extend(_: sealed::Internal, collection: &mut BytesMut, item: T) -> bool {
        collection.put(item);
        true
    }

    fn finalize(_: sealed::Internal, collection: &mut BytesMut) -> BytesMut {
        mem::replace(collection, BytesMut::new())
    }
}

pub(crate) mod sealed {
    #[doc(hidden)]
    pub trait FromStreamPriv<T> {
        /// Intermediate type used during collection process
        ///
        /// The name of this type is internal and cannot be relied upon.
        type InternalCollection;

        /// Initialize the collection
        fn initialize(
            internal: Internal,
            lower: usize,
            upper: Option<usize>,
        ) -> Self::InternalCollection;

        /// Extend the collection with the received item
        ///
        /// Return `true` to continue streaming, `false` complete collection.
        fn extend(internal: Internal, collection: &mut Self::InternalCollection, item: T) -> bool;

        /// Finalize collection into target type.
        fn finalize(internal: Internal, collection: &mut Self::InternalCollection) -> Self;
    }

    #[allow(missing_debug_implementations)]
    pub struct Internal;
}
<|endoftext|>


<commit_before>extern crate rs6502;
extern crate sdl2;

mod ship;
mod timer;

use std::io::{self, BufRead, Write};
use std::path::Path;
use std::sync::mpsc::channel;
use std::thread;
use std::time::Duration;

use rs6502::{Assembler, Cpu, Disassembler};

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::image::LoadTexture;
use sdl2::Sdl;

use ::timer::FrameTimer;

fn main() {
    let (tx, rx) = channel();

    thread::spawn(move || {
        loop {
            std::io::stdout().write(b"HAKKA> ");
            std::io::stdout().flush();

            let mut line = String::new();
            let stdin = io::stdin();
            stdin.lock().read_line(&mut line).expect("Could not read line");
            tx.send(line).unwrap();
        }
    });

    let mut cpu = Cpu::new();
    let mut assembler = Assembler::new();
    let bytecode = assembler.assemble_file("level.asm").unwrap();
    cpu.load(&bytecode[..], None);
    cpu.flags.interrupt_disabled = false;

    cpu.memory[0x02] = 0x80;
    cpu.memory[0x03] = 0x00;
    cpu.memory[0x05] = 0x19;
    cpu.memory[0x06] = 0x00;

    let mut timer = FrameTimer::new(1000 / 120, 0, 0, 0);

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("Hakka", 1280, 400)
        .position_centered()
        .build()
        .unwrap();

    let mut renderer = window.renderer()
        .accelerated()
        .build()
        .unwrap();

    let ship_texture = renderer.load_texture(Path::new("ship.png")).unwrap();

    let mut events = sdl_context.event_pump().unwrap();

    let mut ship = ship::Ship::new(ship_texture);

    'running: loop {

        cpu.step_n(4);
        if let Ok(input) = rx.try_recv() {
            let input = input.trim();
            if input == "exit" {
                break 'running;
            }

            if input == "list" {
                std::io::stdout().write(b"\n");
                std::io::stdout().write(b"-- Disassembly --\n");

                let mut disassembler = Disassembler::with_offset(0xC000);
                let asm = disassembler.disassemble(&bytecode[..]);

                std::io::stdout().write(asm.as_bytes());
                std::io::stdout().write(b"\nHAKKA> ");
                std::io::stdout().flush();
            }
        }

        for event in events.poll_iter() {
            match event {
                Event::Quit { .. } => break 'running,
                Event::KeyDown { keycode: Option::Some(Keycode::Right), .. } => {
                    cpu.memory[0x04] = 39
                }
                Event::KeyDown { keycode: Option::Some(Keycode::Left), .. } => {
                    cpu.memory[0x04] = 37
                }
                Event::KeyUp { keycode: Option::Some(Keycode::Right), .. } => cpu.memory[0x04] = 0,
                Event::KeyUp { keycode: Option::Some(Keycode::Left), .. } => cpu.memory[0x04] = 0,
                Event::KeyDown { keycode: Option::Some(Keycode::Escape), .. } => break 'running,
                _ => (),
            }
        }

        if frame_cap(&sdl_context, &mut timer) {
            ship.process(&cpu.memory[..]);

            if !cpu.flags.interrupt_disabled {
                // Render stuff here
                renderer.clear();
                ship.render(&mut renderer);
                renderer.present();
            }

        }

        if cpu.finished() {
            cpu.reset();
        }

        // thread::sleep(Duration::from_millis(10));
    }
}

fn frame_cap(sdl_context: &Sdl, timer: &mut FrameTimer) -> bool {
    let now = sdl_context.timer().unwrap().ticks();
    let delta = now - timer.prev;
    let elapsed = delta as f64 / 1000.0;

    timer.ticks = now;

    // Wait until 1/60th of a second has passed since we last called this
    if delta < timer.interval {
        sdl_context.timer().unwrap().delay(timer.interval - delta);
        return false;
    }

    timer.prev = now;
    timer.fps += 1;

    timer.elapsed = elapsed;

    if now - timer.last_second > 1000 {
        // Store our current FPS
        timer.last_fps = timer.fps;
        timer.last_second = now;
        timer.fps = 0;
    }

    true
}<commit_msg>Add crude memory monitoring functionality<commit_after>extern crate rs6502;
extern crate sdl2;

mod ship;
mod timer;

use std::io::{self, BufRead, Write};
use std::path::Path;
use std::sync::mpsc::channel;
use std::thread;
use std::time::Duration;

use rs6502::{Assembler, Cpu, Disassembler};

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::image::LoadTexture;
use sdl2::Sdl;

use ::timer::FrameTimer;

fn main() {
    let (tx, rx) = channel();

    thread::spawn(move || {
        loop {
            std::io::stdout().write(b"HAKKA> ");
            std::io::stdout().flush();

            let mut line = String::new();
            let stdin = io::stdin();
            stdin.lock().read_line(&mut line).expect("Could not read line");
            tx.send(line).unwrap();
        }
    });

    let mut cpu = Cpu::new();
    let mut assembler = Assembler::new();
    let bytecode = assembler.assemble_file("level.asm").unwrap();
    cpu.load(&bytecode[..], None);
    cpu.flags.interrupt_disabled = false;

    cpu.memory[0x02] = 0x80;
    cpu.memory[0x03] = 0x00;
    cpu.memory[0x05] = 0x19;
    cpu.memory[0x06] = 0x00;

    let mut timer = FrameTimer::new(1000 / 120, 0, 0, 0);

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("Hakka", 1280, 400)
        .position_centered()
        .build()
        .unwrap();

    let mut renderer = window.renderer()
        .accelerated()
        .build()
        .unwrap();

    let ship_texture = renderer.load_texture(Path::new("ship.png")).unwrap();

    let mut events = sdl_context.event_pump().unwrap();

    let mut ship = ship::Ship::new(ship_texture);

    let mut monitor_enabled = false;
    let mut monitor_last = 0;

    'running: loop {

        cpu.step_n(4);
        if let Ok(input) = rx.try_recv() {
            let input = input.trim();
            if input == "exit" {
                break 'running;
            }

            if input == "list" {
                std::io::stdout().write(b"\n");
                std::io::stdout().write(b"-- Disassembly --\n");

                let mut disassembler = Disassembler::with_offset(0xC000);
                let asm = disassembler.disassemble(&bytecode[..]);

                std::io::stdout().write(asm.as_bytes());
                std::io::stdout().write(b"\nHAKKA> ");
                std::io::stdout().flush();
            }

            if input == "monitor" {
                monitor_enabled = !monitor_enabled;
            }
        }

        for event in events.poll_iter() {
            match event {
                Event::Quit { .. } => break 'running,
                Event::KeyDown { keycode: Option::Some(Keycode::Right), .. } => {
                    cpu.memory[0x04] = 39
                }
                Event::KeyDown { keycode: Option::Some(Keycode::Left), .. } => {
                    cpu.memory[0x04] = 37
                }
                Event::KeyUp { keycode: Option::Some(Keycode::Right), .. } => cpu.memory[0x04] = 0,
                Event::KeyUp { keycode: Option::Some(Keycode::Left), .. } => cpu.memory[0x04] = 0,
                Event::KeyDown { keycode: Option::Some(Keycode::Escape), .. } => break 'running,
                _ => (),
            }
        }

        if frame_cap(&sdl_context, &mut timer) {
            ship.process(&cpu.memory[..]);

            if !cpu.flags.interrupt_disabled {
                // Render stuff here
                renderer.clear();
                ship.render(&mut renderer);
                renderer.present();
            }
        }

        let now = sdl_context.timer().unwrap().ticks();
        let delta = now - monitor_last;
        if delta > 1000 && monitor_enabled {
            println!("{:?}", &cpu.memory[0x00..0xA]);
            monitor_last = now;
        }

        if cpu.finished() {
            cpu.reset();
        }

        // thread::sleep(Duration::from_millis(10));
    }
}

fn frame_cap(sdl_context: &Sdl, timer: &mut FrameTimer) -> bool {
    let now = sdl_context.timer().unwrap().ticks();
    let delta = now - timer.prev;
    let elapsed = delta as f64 / 1000.0;

    timer.ticks = now;

    // Wait until 1/60th of a second has passed since we last called this
    if delta < timer.interval {
        sdl_context.timer().unwrap().delay(timer.interval - delta);
        return false;
    }

    timer.prev = now;
    timer.fps += 1;

    timer.elapsed = elapsed;

    if now - timer.last_second > 1000 {
        // Store our current FPS
        timer.last_fps = timer.fps;
        timer.last_second = now;
        timer.fps = 0;
    }

    true
}<|endoftext|>


<commit_before>extern crate rs6502;
extern crate sdl2;

mod ship;
mod timer;

use std::io::{self, BufRead, Write};
use std::path::Path;
use std::sync::mpsc::channel;
use std::thread;
use std::time::Duration;

use rs6502::{Assembler, Cpu, Disassembler};

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::image::LoadTexture;
use sdl2::Sdl;

use ::timer::FrameTimer;

fn main() {
    let (tx, rx) = channel();

    thread::spawn(move || {
        loop {
            std::io::stdout().write(b"HAKKA> ");
            std::io::stdout().flush();

            let mut line = String::new();
            let stdin = io::stdin();
            stdin.lock().read_line(&mut line).expect("Could not read line");
            tx.send(line).unwrap();
        }
    });

    let mut cpu = Cpu::new();
    let mut assembler = Assembler::new();
    let bytecode = assembler.assemble_file("level.asm").unwrap();
    cpu.load(&bytecode[..], None);
    cpu.flags.interrupt_disabled = false;

    cpu.memory[0x02] = 0x80;
    cpu.memory[0x03] = 0x00;
    cpu.memory[0x05] = 0x19;
    cpu.memory[0x06] = 0x00;

    let mut timer = FrameTimer::new(1000 / 240, 0, 0, 0);

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("Hakka", 1280, 400)
        .position_centered()
        .build()
        .unwrap();

    let mut renderer = window.renderer()
        .accelerated()
        .build()
        .unwrap();

    let ship_texture = renderer.load_texture(Path::new("ship.png")).unwrap();

    let mut events = sdl_context.event_pump().unwrap();

    let mut ship = ship::Ship::new(ship_texture);

    let mut monitor_enabled = false;
    let mut monitor_last = 0;

    'running: loop {
        cpu.step();

        if let Ok(input) = rx.try_recv() {
            let input = input.trim();
            if input == "exit" {
                break 'running;
            }

            if input == "list" {
                std::io::stdout().write(b"\n");
                std::io::stdout().write(b"-- Disassembly --\n");

                let mut disassembler = Disassembler::with_offset(0xC000);
                let asm = disassembler.disassemble(&bytecode[..]);

                std::io::stdout().write(asm.as_bytes());
                std::io::stdout().write(b"\nHAKKA> ");
                std::io::stdout().flush();
            }

            if input == "monitor" {
                monitor_enabled = !monitor_enabled;
            }
        }

        for event in events.poll_iter() {
            match event {
                Event::Quit { .. } => break 'running,
                Event::KeyDown { keycode: Option::Some(Keycode::Right), .. } => {
                    cpu.memory[0x04] = 39
                }
                Event::KeyDown { keycode: Option::Some(Keycode::Left), .. } => {
                    cpu.memory[0x04] = 37
                }
                Event::KeyUp { keycode: Option::Some(Keycode::Right), .. } => cpu.memory[0x04] = 0,
                Event::KeyUp { keycode: Option::Some(Keycode::Left), .. } => cpu.memory[0x04] = 0,
                Event::KeyDown { keycode: Option::Some(Keycode::Escape), .. } => break 'running,
                _ => (),
            }
        }

        ship.process(&cpu.memory[..]);

        if frame_cap(&sdl_context, &mut timer) {

            if !cpu.flags.interrupt_disabled {
                // Render stuff here
                renderer.clear();
                ship.render(&mut renderer);
                renderer.present();
            }
        }

        let now = sdl_context.timer().unwrap().ticks();
        let delta = now - monitor_last;
        if delta > 1000 && monitor_enabled {
            println!("{:?}", &cpu.memory[0x00..0xA]);
            monitor_last = now;
        }

        // thread::sleep(Duration::from_millis(10));
    }
}

fn frame_cap(sdl_context: &Sdl, timer: &mut FrameTimer) -> bool {
    let now = sdl_context.timer().unwrap().ticks();
    let delta = now - timer.prev;
    let elapsed = delta as f64 / 1000.0;

    timer.ticks = now;

    // Wait until 1/60th of a second has passed since we last called this
    if delta < timer.interval {
        sdl_context.timer().unwrap().delay(timer.interval - delta);
        return false;
    }

    timer.prev = now;
    timer.fps += 1;

    timer.elapsed = elapsed;

    if now - timer.last_second > 1000 {
        // Store our current FPS
        timer.last_fps = timer.fps;
        timer.last_second = now;
        timer.fps = 0;
    }

    true
}<commit_msg>Clean monitor output<commit_after>extern crate rs6502;
extern crate sdl2;

mod ship;
mod timer;

use std::io::{self, BufRead, Write};
use std::path::Path;
use std::sync::mpsc::channel;
use std::thread;
use std::time::Duration;

use rs6502::{Assembler, Cpu, Disassembler};

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::image::LoadTexture;
use sdl2::Sdl;

use ::timer::FrameTimer;

fn main() {
    let (tx, rx) = channel();

    thread::spawn(move || {
        loop {
            std::io::stdout().write(b"HAKKA> ");
            std::io::stdout().flush();

            let mut line = String::new();
            let stdin = io::stdin();
            stdin.lock().read_line(&mut line).expect("Could not read line");
            tx.send(line).unwrap();
        }
    });

    let mut cpu = Cpu::new();
    let mut assembler = Assembler::new();
    let bytecode = assembler.assemble_file("level.asm").unwrap();
    cpu.load(&bytecode[..], None);
    cpu.flags.interrupt_disabled = false;

    cpu.memory[0x02] = 0x80;
    cpu.memory[0x03] = 0x00;
    cpu.memory[0x05] = 0x19;
    cpu.memory[0x06] = 0x00;

    let mut timer = FrameTimer::new(1000 / 240, 0, 0, 0);

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("Hakka", 1280, 400)
        .position_centered()
        .build()
        .unwrap();

    let mut renderer = window.renderer()
        .accelerated()
        .build()
        .unwrap();

    let ship_texture = renderer.load_texture(Path::new("ship.png")).unwrap();

    let mut events = sdl_context.event_pump().unwrap();

    let mut ship = ship::Ship::new(ship_texture);

    let mut monitor_enabled = false;
    let mut monitor_last = 0;

    'running: loop {
        cpu.step();

        if let Ok(input) = rx.try_recv() {
            let input = input.trim();
            if input == "exit" {
                break 'running;
            }

            if input == "list" {
                std::io::stdout().write(b"\n");
                std::io::stdout().write(b"-- Disassembly --\n");

                let mut disassembler = Disassembler::with_offset(0xC000);
                let asm = disassembler.disassemble(&bytecode[..]);

                std::io::stdout().write(asm.as_bytes());
                std::io::stdout().write(b"\nHAKKA> ");
                std::io::stdout().flush();
            }

            if input == "monitor" {
                monitor_enabled = !monitor_enabled;
            }
        }

        ship.process(&cpu.memory[..]);

        for event in events.poll_iter() {
            match event {
                Event::Quit { .. } => break 'running,
                Event::KeyDown { keycode: Option::Some(Keycode::Right), .. } => {
                    cpu.memory[0x04] = 39
                }
                Event::KeyDown { keycode: Option::Some(Keycode::Left), .. } => {
                    cpu.memory[0x04] = 37
                }
                Event::KeyUp { keycode: Option::Some(Keycode::Right), .. } => cpu.memory[0x04] = 0,
                Event::KeyUp { keycode: Option::Some(Keycode::Left), .. } => cpu.memory[0x04] = 0,
                Event::KeyDown { keycode: Option::Some(Keycode::Escape), .. } => break 'running,
                _ => (),
            }
        }

        if frame_cap(&sdl_context, &mut timer) {

            if !cpu.flags.interrupt_disabled {
                // Render stuff here
                renderer.clear();
                ship.render(&mut renderer);
                renderer.present();
            }
        }

        let now = sdl_context.timer().unwrap().ticks();
        let delta = now - monitor_last;
        if delta > 1000 && monitor_enabled {
            for b in &cpu.memory[0x00..0xA] {
                print!("{:02X} ", *b);
            }
            println!("");
            monitor_last = now;
        }

        // thread::sleep(Duration::from_millis(10));
    }
}

fn frame_cap(sdl_context: &Sdl, timer: &mut FrameTimer) -> bool {
    let now = sdl_context.timer().unwrap().ticks();
    let delta = now - timer.prev;
    let elapsed = delta as f64 / 1000.0;

    timer.ticks = now;

    // Wait until 1/60th of a second has passed since we last called this
    if delta < timer.interval {
        sdl_context.timer().unwrap().delay(timer.interval - delta);
        return false;
    }

    timer.prev = now;
    timer.fps += 1;

    timer.elapsed = elapsed;

    if now - timer.last_second > 1000 {
        // Store our current FPS
        timer.last_fps = timer.fps;
        timer.last_second = now;
        timer.fps = 0;
    }

    true
}<|endoftext|>