<commit_before>use super::*;
use linked_hash_map::LinkedHashMap;

/// Cut down version of a [`GlyphBrush`](struct.GlyphBrush.html) that can calculate pixel bounds,
/// but is unable to actually render anything.
///
/// Build using a [`HeadlessGlyphBrushBuilder`](struct.HeadlessGlyphBrushBuilder.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::{HeadlessGlyphBrushBuilder, Section};
/// # fn main() {
///
/// let arial: &[u8] = include_bytes!("../examples/Arial Unicode.ttf");
/// let mut glyphs = HeadlessGlyphBrushBuilder::using_font_bytes(arial).build();
///
/// let section = Section {
///     text: "Hello gfx_glyph",
///     ..Section::default()
/// };
///
/// let bounds = glyphs.pixel_bounds(section);
/// # let _ = bounds;
/// # let _ = glyphs;
/// # }
/// ```
///
/// # Caching behaviour
///
/// Calls to [`GlyphBrush::pixel_bounds`](#method.pixel_bounds),
/// [`GlyphBrush::glyphs`](#method.glyphs) calculate the positioned glyphs for a section.
/// This is cached so future calls to any of the methods for the same section are much
/// cheaper.
///
/// Unlike a [`GlyphBrush`](struct.GlyphBrush.html) the cache has a maximum size and evicts
/// older sections when full, this is because there is no concept of actually drawing the section
/// to imply a section is no longer used.
/// [`HeadlessGlyphBrushBuilder::glyph_positioning_cache_size`](struct.HeadlessGlyphBrushBuilder.html#method.glyph_positioning_cache_size)
/// allows setting the maximum cache size.
pub struct HeadlessGlyphBrush<'font> {
    fonts: HashMap<FontId, rusttype::Font<'font>>,

    // cache of section-layout hash -> computed glyphs, this avoid repeated glyph computation
    // for identical layout/sections common to repeated frame rendering
    calculate_glyph_cache: LinkedHashMap<u64, GlyphedSection<'font>>,

    glyph_positioning_cache_size: usize,
}

impl<'font> HeadlessGlyphBrush<'font> {

    /// Returns the pixel bounding box for the input section using a custom layout.
    /// The box is a conservative whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn pixel_bounds_custom_layout<'a, S, L>(&mut self, section: S, custom_layout: &L)
        -> Option<Rect<i32>>
        where L: GlyphPositioner + Hash,
              S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let mut x = (0, 0);
        let mut y = (0, 0);
        let mut no_match = true;

        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);

        for g in self.calculate_glyph_cache[&section_hash]
            .glyphs.iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
        {
            if let Some(Rect{ min, max }) = g.pixel_bounding_box() {
                if no_match || min.x < x.0 { x.0 = min.x; }
                if no_match || min.y < y.0 { y.0 = min.y; }
                if no_match || max.x > x.1 { x.1 = max.x; }
                if no_match || max.y > y.1 { y.1 = max.y; }

                no_match = false;
            }
        }

        if no_match { None }
        else {
            Some(Rect {
                min: Point { x: x.0, y: y.0 },
                max: Point { x: x.1, y: y.1 },
            })
        }
    }

    /// Returns the pixel bounding box for the input section. The box is a conservative
    /// whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn pixel_bounds<'a, S>(&mut self, section: S)
        -> Option<Rect<i32>>
        where S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.pixel_bounds_custom_layout(section, &layout)
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section with a custom layout.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn glyphs_custom_layout<'a, 'b, S, L>(&'b mut self, section: S, custom_layout: &L)
        -> PositionedGlyphIter<'b, 'font>
        where L: GlyphPositioner + Hash,
              S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);
        self.calculate_glyph_cache[&section_hash]
            .glyphs.iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn glyphs<'a, 'b, S>(&'b mut self, section: S)
        -> PositionedGlyphIter<'b, 'font>
        where S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.glyphs_custom_layout(section, &layout)
    }

    /// Returns the calculate_glyph_cache key for this sections glyphs
    fn cache_glyphs<L>(&mut self, section: &VariedSection, layout: &L) -> u64
        where L: GlyphPositioner,
    {
        let section_hash = hash(&(section, layout));

        if self.calculate_glyph_cache.get_refresh(&section_hash).is_none() {
            self.calculate_glyph_cache.insert(section_hash, GlyphedSection {
                bounds: layout.bounds_rect(section),
                glyphs: layout.calculate_glyphs(&self.fonts, section),
                z: section.z,
            });
        }
        else {
            while self.calculate_glyph_cache.len() > self.glyph_positioning_cache_size {
                self.calculate_glyph_cache.pop_front();
            }
        }

        section_hash
    }
}

/// Builder for a [`HeadlessGlyphBrush`](struct.HeadlessGlyphBrush.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::HeadlessGlyphBrushBuilder;
/// # fn main() {
///
/// let arial: &[u8] = include_bytes!("../examples/Arial Unicode.ttf");
/// let mut glyphs = HeadlessGlyphBrushBuilder::using_font_bytes(arial).build();
/// # let _ = glyphs;
/// # }
/// ```
pub struct HeadlessGlyphBrushBuilder<'a> {
    font_data: Vec<Font<'a>>,
    glyph_positioning_cache_size: usize,
}

impl<'a> HeadlessGlyphBrushBuilder<'a> {
    /// Specifies the default font data used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font_bytes<B: Into<SharedBytes<'a>>>(font_0_data: B) -> Self {
        Self::using_font(font(font_0_data).unwrap())
    }

    /// Specifies the default font used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font(font_0_data: Font<'a>) -> Self {
        Self {
            font_data: vec![font_0_data],
            glyph_positioning_cache_size: 50,
        }
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font_bytes<B: Into<SharedBytes<'a>>>(&mut self, font_data: B) -> FontId {
        self.font_data.push(font(font_data.into()).unwrap());
        FontId(self.font_data.len() - 1)
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font(&mut self, font_data: Font<'a>) -> FontId {
        self.font_data.push(font_data);
        FontId(self.font_data.len() - 1)
    }

    /// Sets the max number of unique sections to cache positioning data. After processing
    /// over this amount of sections oldest section positioning data will be evicted from the cache.
    ///
    /// Defaults to 50
    pub fn glyph_positioning_cache_size(mut self, entries: usize) -> Self {
        self.glyph_positioning_cache_size = entries;
        self
    }

    /// Builds a `HeadlessGlyphBrush`
    pub fn build(self) -> HeadlessGlyphBrush<'a> {
        let fonts = self.font_data.into_iter().enumerate()
            .map(|(idx, data)| (FontId(idx), data))
            .collect();

        let cache = LinkedHashMap::with_capacity(self.glyph_positioning_cache_size + 1);

        HeadlessGlyphBrush {
            fonts,
            calculate_glyph_cache: cache,
            glyph_positioning_cache_size: self.glyph_positioning_cache_size,
        }
    }
}
<commit_msg>Add headless brush `clear_cache`<commit_after>use super::*;
use linked_hash_map::LinkedHashMap;

/// Cut down version of a [`GlyphBrush`](struct.GlyphBrush.html) that can calculate pixel bounds,
/// but is unable to actually render anything.
///
/// Build using a [`HeadlessGlyphBrushBuilder`](struct.HeadlessGlyphBrushBuilder.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::{HeadlessGlyphBrushBuilder, Section};
/// # fn main() {
///
/// let arial: &[u8] = include_bytes!("../examples/Arial Unicode.ttf");
/// let mut glyphs = HeadlessGlyphBrushBuilder::using_font_bytes(arial).build();
///
/// let section = Section {
///     text: "Hello gfx_glyph",
///     ..Section::default()
/// };
///
/// let bounds = glyphs.pixel_bounds(section);
/// # let _ = bounds;
/// # let _ = glyphs;
/// # }
/// ```
///
/// # Caching behaviour
///
/// Calls to [`GlyphBrush::pixel_bounds`](#method.pixel_bounds),
/// [`GlyphBrush::glyphs`](#method.glyphs) calculate the positioned glyphs for a section.
/// This is cached so future calls to any of the methods for the same section are much
/// cheaper.
///
/// Unlike a [`GlyphBrush`](struct.GlyphBrush.html) the cache has a maximum size and evicts
/// older sections when full, this is because there is no concept of actually drawing the section
/// to imply a section is no longer used.
/// [`HeadlessGlyphBrushBuilder::glyph_positioning_cache_size`](struct.HeadlessGlyphBrushBuilder.html#method.glyph_positioning_cache_size)
/// allows setting the maximum cache size.
pub struct HeadlessGlyphBrush<'font> {
    fonts: HashMap<FontId, rusttype::Font<'font>>,

    // cache of section-layout hash -> computed glyphs, this avoid repeated glyph computation
    // for identical layout/sections common to repeated frame rendering
    calculate_glyph_cache: LinkedHashMap<u64, GlyphedSection<'font>>,

    glyph_positioning_cache_size: usize,
}

impl<'font> HeadlessGlyphBrush<'font> {

    /// Returns the pixel bounding box for the input section using a custom layout.
    /// The box is a conservative whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn pixel_bounds_custom_layout<'a, S, L>(&mut self, section: S, custom_layout: &L)
        -> Option<Rect<i32>>
        where L: GlyphPositioner + Hash,
              S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let mut x = (0, 0);
        let mut y = (0, 0);
        let mut no_match = true;

        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);

        for g in self.calculate_glyph_cache[&section_hash]
            .glyphs.iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
        {
            if let Some(Rect{ min, max }) = g.pixel_bounding_box() {
                if no_match || min.x < x.0 { x.0 = min.x; }
                if no_match || min.y < y.0 { y.0 = min.y; }
                if no_match || max.x > x.1 { x.1 = max.x; }
                if no_match || max.y > y.1 { y.1 = max.y; }

                no_match = false;
            }
        }

        if no_match { None }
        else {
            Some(Rect {
                min: Point { x: x.0, y: y.0 },
                max: Point { x: x.1, y: y.1 },
            })
        }
    }

    /// Returns the pixel bounding box for the input section. The box is a conservative
    /// whole number pixel rectangle that can contain the section.
    ///
    /// If the section is empty or would result in no drawn glyphs will return `None`
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn pixel_bounds<'a, S>(&mut self, section: S)
        -> Option<Rect<i32>>
        where S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.pixel_bounds_custom_layout(section, &layout)
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section with a custom layout.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn glyphs_custom_layout<'a, 'b, S, L>(&'b mut self, section: S, custom_layout: &L)
        -> PositionedGlyphIter<'b, 'font>
        where L: GlyphPositioner + Hash,
              S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let section_hash = self.cache_glyphs(section.borrow(), custom_layout);
        self.calculate_glyph_cache[&section_hash]
            .glyphs.iter()
            .flat_map(|&GlyphedSectionText(ref g, ..)| g.iter())
    }

    /// Returns an iterator over the `PositionedGlyph`s of the given section.
    ///
    /// Benefits from caching, see [caching behaviour](#caching-behaviour).
    pub fn glyphs<'a, 'b, S>(&'b mut self, section: S)
        -> PositionedGlyphIter<'b, 'font>
        where S: Into<Cow<'a, VariedSection<'a>>>,
    {
        let section = section.into();
        let layout = section.layout;
        self.glyphs_custom_layout(section, &layout)
    }

    /// Returns the calculate_glyph_cache key for this sections glyphs
    fn cache_glyphs<L>(&mut self, section: &VariedSection, layout: &L) -> u64
        where L: GlyphPositioner,
    {
        let section_hash = hash(&(section, layout));

        if self.calculate_glyph_cache.get_refresh(&section_hash).is_none() {
            self.calculate_glyph_cache.insert(section_hash, GlyphedSection {
                bounds: layout.bounds_rect(section),
                glyphs: layout.calculate_glyphs(&self.fonts, section),
                z: section.z,
            });
        }
        else {
            while self.calculate_glyph_cache.len() > self.glyph_positioning_cache_size {
                self.calculate_glyph_cache.pop_front();
            }
        }

        section_hash
    }

    /// Invalidates any cached computations.
    ///
    /// This is useful if environment values outside of passed section/layout data
    /// has changed, e.g. screen resolution.
    pub fn clear_cache(&mut self) {
        self.calculate_glyph_cache.clear();
    }
}

/// Builder for a [`HeadlessGlyphBrush`](struct.HeadlessGlyphBrush.html).
///
/// # Example
///
/// ```no_run
/// # extern crate gfx;
/// # extern crate gfx_window_glutin;
/// # extern crate glutin;
/// extern crate gfx_glyph;
/// use gfx_glyph::HeadlessGlyphBrushBuilder;
/// # fn main() {
///
/// let arial: &[u8] = include_bytes!("../examples/Arial Unicode.ttf");
/// let mut glyphs = HeadlessGlyphBrushBuilder::using_font_bytes(arial).build();
/// # let _ = glyphs;
/// # }
/// ```
pub struct HeadlessGlyphBrushBuilder<'a> {
    font_data: Vec<Font<'a>>,
    glyph_positioning_cache_size: usize,
}

impl<'a> HeadlessGlyphBrushBuilder<'a> {
    /// Specifies the default font data used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font_bytes<B: Into<SharedBytes<'a>>>(font_0_data: B) -> Self {
        Self::using_font(font(font_0_data).unwrap())
    }

    /// Specifies the default font used to render glyphs.
    /// Referenced with `FontId(0)`, which is default.
    pub fn using_font(font_0_data: Font<'a>) -> Self {
        Self {
            font_data: vec![font_0_data],
            glyph_positioning_cache_size: 50,
        }
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font_bytes<B: Into<SharedBytes<'a>>>(&mut self, font_data: B) -> FontId {
        self.font_data.push(font(font_data.into()).unwrap());
        FontId(self.font_data.len() - 1)
    }

    /// Adds additional fonts to the one added in [`using_font`](#method.using_font) /
    /// [`using_font_bytes`](#method.using_font_bytes).
    /// Returns a [`FontId`](struct.FontId.html) to reference this font.
    pub fn add_font(&mut self, font_data: Font<'a>) -> FontId {
        self.font_data.push(font_data);
        FontId(self.font_data.len() - 1)
    }

    /// Sets the max number of unique sections to cache positioning data. After processing
    /// over this amount of sections oldest section positioning data will be evicted from the cache.
    ///
    /// Defaults to 50
    pub fn glyph_positioning_cache_size(mut self, entries: usize) -> Self {
        self.glyph_positioning_cache_size = entries;
        self
    }

    /// Builds a `HeadlessGlyphBrush`
    pub fn build(self) -> HeadlessGlyphBrush<'a> {
        let fonts = self.font_data.into_iter().enumerate()
            .map(|(idx, data)| (FontId(idx), data))
            .collect();

        let cache = LinkedHashMap::with_capacity(self.glyph_positioning_cache_size + 1);

        HeadlessGlyphBrush {
            fonts,
            calculate_glyph_cache: cache,
            glyph_positioning_cache_size: self.glyph_positioning_cache_size,
        }
    }
}
<|endoftext|>


<commit_before>extern crate dailyschedule;
extern crate daylight;
extern crate time;

use dailyschedule::*;
use time::{Timespec, at, at_utc, now_utc, Duration};
use daylight::calculate_daylight;
use std::cell::RefCell;

const ON: ScheduleContext = ScheduleContext(0);
const OFF: ScheduleContext = ScheduleContext(1);
const LAT: f64 = 52.0 + 13.0/60.0;
const LONG: f64 = 5.0 + 58.0/60.0;

#[derive(Eq, PartialEq)]
enum SwitchState {
    Off,
    On
}
enum SwitchScheduleState {
    DeepOff,
    Off,
    On
}

struct PrintAction {
    id: String,
    switch_depth: SwitchScheduleState,
    cur_state: SwitchState
}

impl PrintAction {
    fn new(name: &str) -> PrintAction {
        PrintAction {
            id: name.to_string(),
            switch_depth: SwitchScheduleState::Off,
            cur_state: SwitchState::Off
        }
    }
}

impl ScheduleAction for PrintAction {
    fn kick(&mut self, timestamp: &Timespec, event: &ScheduleMoment, context: &ScheduleContext) {
        self.switch_depth = match context {
            &ON => match self.switch_depth {
                SwitchScheduleState::DeepOff => SwitchScheduleState::Off,
                SwitchScheduleState::Off => SwitchScheduleState::On,
                SwitchScheduleState::On => SwitchScheduleState::On
            },
            &OFF => match self.switch_depth {
                SwitchScheduleState::DeepOff => SwitchScheduleState::DeepOff,
                SwitchScheduleState::Off => SwitchScheduleState::DeepOff,
                SwitchScheduleState::On => SwitchScheduleState::Off
            },
            _ => unreachable!()
        };
        let new_state = match self.switch_depth {
            SwitchScheduleState::DeepOff | SwitchScheduleState::Off => SwitchState::Off,
            SwitchScheduleState::On => SwitchState::On
        };
        if new_state != self.cur_state {
            let action = match new_state {
                SwitchState::Off => "off:",
                SwitchState::On => "on:"
            };
            println!("{} {:5}{} {}", self.id, action, at(*timestamp).rfc822(), event);
            self.cur_state = new_state;
        }
    }
}

fn main() {
    let sunrise_closure = |ts| ScheduleTime::new_from_timespec(calculate_daylight(at_utc(ts), LAT, LONG).sunrise);

    //let action_handler_1 = RefCell::new(Box::new(PrintAction::new("1")) as Box<dailyschedule::ScheduleAction>);
    let action_handler_1 = RefCell::new(PrintAction::new("1"));
    //let action_handler_2 = PrintAction::new("2");
    //let action_handler_3 = PrintAction::new("3");
    //let action_handler_4 = PrintAction::new("4");

    let mut schedule = Schedule::<PrintAction>::new().unwrap();

    schedule.add_event(
        ScheduleMoment::Fuzzy(ScheduleTime::new(6,20,0), ScheduleTime::new(6,40,1)),
        &action_handler_1,
        ON);
    schedule.add_event(
        ScheduleMoment::ByClosure(&sunrise_closure, Duration::minutes(2)),
        &action_handler_1,
        OFF);

    //schedule.add_event(ScheduleMoment::Fuzzy(ScheduleTime::new(10,0,0),
    //                                         ScheduleTime::new(11,0,0)), &action_handler_1, ON);
    //schedule.add_event(ScheduleMoment::Fuzzy(ScheduleTime::new(12,0,0),
    //                                         ScheduleTime::new(13,0,0)), &action_handler_1, OFF);
    //schedule.add_event(ScheduleMoment::ByClosure(Box::new(|_| ScheduleTime::new(14,0,0)), Duration::minutes(1)), &action_handler_2, ON);
    //schedule.add_event(ScheduleMoment::ByClosure(Box::new(|_| ScheduleTime::new(15,0,0)), Duration::minutes(1)), &action_handler_2, OFF);
    //schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(19,0,0)), &action_handler_3, ON);
    //schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(21,0,0)), &action_handler_3, OFF);
    //schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(22,0,0)), &action_handler_4, ON);
    //schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(23,0,0)), &action_handler_4, OFF);

    let mut tm = now_utc();
    tm.tm_hour = 0;
    tm.tm_min = 0;
    tm.tm_sec = 0;
    tm.tm_nsec = 0;
    let ts_ref = tm.to_timespec();

    for days in 0..366 {
        schedule.update_schedule(ts_ref + Duration::days(days));
    }

    let mut now = Timespec::new(0,0);

    loop {
        match schedule.kick_event(now) {
            Some(next) => {
                now = next;
            }
            None => break
        }
    }

    //schedule.print_keys();
    //schedule.kick_event(Timespec::new(15*3600, 0));
    //schedule.print_keys();
}
<commit_msg>schedule_printer: cleanup example<commit_after>extern crate dailyschedule;
extern crate daylight;
extern crate time;

use dailyschedule::*;
use time::{Timespec, at, at_utc, now_utc, Duration};
use daylight::calculate_daylight;
use std::cell::RefCell;

const ON: ScheduleContext = ScheduleContext(0);
const OFF: ScheduleContext = ScheduleContext(1);
const LAT: f64 = 52.0 + 13.0/60.0;
const LONG: f64 = 5.0 + 58.0/60.0;

#[derive(Eq, PartialEq)]
enum SwitchState {
    Off,
    On
}
enum SwitchScheduleState {
    DeepOff,
    Off,
    On
}

struct PrintAction {
    id: String,
    switch_depth: SwitchScheduleState,
    cur_state: SwitchState
}

impl PrintAction {
    fn new(name: &str) -> PrintAction {
        PrintAction {
            id: name.to_string(),
            switch_depth: SwitchScheduleState::Off,
            cur_state: SwitchState::Off
        }
    }

    fn as_ref(name: &str) -> RefCell<PrintAction> {
        RefCell::new(PrintAction::new(name))
    }
}

impl ScheduleAction for PrintAction {
    fn kick(&mut self, timestamp: &Timespec, event: &ScheduleMoment, context: &ScheduleContext) {
        self.switch_depth = match context {
            &ON => match self.switch_depth {
                SwitchScheduleState::DeepOff => SwitchScheduleState::Off,
                SwitchScheduleState::Off => SwitchScheduleState::On,
                SwitchScheduleState::On => SwitchScheduleState::On
            },
            &OFF => match self.switch_depth {
                SwitchScheduleState::DeepOff => SwitchScheduleState::DeepOff,
                SwitchScheduleState::Off => SwitchScheduleState::DeepOff,
                SwitchScheduleState::On => SwitchScheduleState::Off
            },
            _ => unreachable!()
        };
        let new_state = match self.switch_depth {
            SwitchScheduleState::DeepOff | SwitchScheduleState::Off => SwitchState::Off,
            SwitchScheduleState::On => SwitchState::On
        };
        if new_state != self.cur_state {
            let action = match new_state {
                SwitchState::Off => "off:",
                SwitchState::On => "on:"
            };
            println!("{} {:5}{} {}", self.id, action, at_utc(*timestamp).rfc822(), event);
            self.cur_state = new_state;
        }
    }
}

fn main() {
    let sunrise_closure = |ts| ScheduleTime::new_from_timespec(calculate_daylight(at_utc(ts), LAT, LONG).sunrise);
    let sunset_closure = |ts| ScheduleTime::new_from_timespec(calculate_daylight(at_utc(ts), LAT, LONG).sunset);

    let action_handler_1 = PrintAction::as_ref("1");
    let action_handler_2 = PrintAction::as_ref("2");

    let mut schedule = Schedule::<PrintAction>::new().unwrap();

    schedule.add_event(
        ScheduleMoment::Fuzzy(ScheduleTime::new(6,20,0), ScheduleTime::new(6,40,0)),
        &action_handler_1,
        ON);
    schedule.add_event(
        ScheduleMoment::ByClosure(&sunrise_closure, Duration::minutes(2)),
        &action_handler_1,
        OFF);

    schedule.add_event(
        ScheduleMoment::ByClosure(&sunset_closure, Duration::minutes(10)),
        &action_handler_2,
        ON);
    schedule.add_event(
        ScheduleMoment::Fuzzy(ScheduleTime::new(0,15,0), ScheduleTime::new(0,30,0)),
        &action_handler_2,
        OFF);

    let mut tm = now_utc();
    tm.tm_hour = 0;
    tm.tm_min = 0;
    tm.tm_sec = 0;
    tm.tm_nsec = 0;
    let ts_ref = tm.to_timespec();

    for days in 0..730 {
        schedule.update_schedule(ts_ref + Duration::days(days));
    }

    let mut now = now_utc().to_timespec();

    loop {
        match schedule.kick_event(now) {
            Some(next) => {
                now = next;
            }
            None => break
        }
    }
}
<|endoftext|>


<commit_before>mod drawable;
mod level;
mod shape;

use self::level::Level;

use errors::*;
use moho::input_manager::InputManager;
use moho::resource_manager::{ResourceManager, Texture};
use moho::timer::Timer;
use moho::MohoEngine;
use sdl2::keyboard::Keycode;

use std::time::Duration;

pub struct MasterSmasher<E: MohoEngine> {
    level: Level,
    background: Texture,
    input_manager: InputManager<E::EventPump>,
    renderer: ResourceManager<E::Renderer>,
}

impl<E: MohoEngine> MasterSmasher<E> {
    pub fn new(mut renderer: ResourceManager<E::Renderer>,
               input_manager: InputManager<E::EventPump>)
               -> Result<Self> {
        let background = renderer.load_texture("resources/background_game.png")?;
        let window_size = renderer.output_size()?;
        renderer.wrap_coords = Some(window_size);
        let level = Level::load("levels/level_1.lvl", window_size, &renderer)?;
        Ok(MasterSmasher {
               level: level,
               background: background,
               input_manager: input_manager,
               renderer: renderer,
           })
    }

    pub fn run(&mut self) -> Result<()> {
        const GAME_SPEED: u32 = 60;
        const MAX_SKIP: u32 = 10;
        let update_duration = Duration::new(0, 1000000000 / GAME_SPEED);
        let mut timer = Timer::new();
        let mut delta: Duration = Default::default();
        while !self.game_quit() {
            let game_time = timer.update();
            delta += game_time.since_update;
            let mut loops: u32 = 0;
            while delta >= update_duration && loops < MAX_SKIP {
                self.input_manager.update();
                if self.game_quit() {
                    break;
                }
                self.update();
                delta -= update_duration;
                loops += 1;
            }
            if self.game_quit() {
                break;
            }
            self.level.animate(game_time.since_update);
            let interpolation = delta.subsec_nanos() as f64 / update_duration.subsec_nanos() as f64;
            self.draw(interpolation)?;
        }
        Ok(())
    }

    fn update(&mut self) {
        self.level.update(&self.input_manager);
    }

    fn draw(&mut self, interpolation: f64) -> Result<()> {
        self.renderer.clear();
        self.renderer.draw(self.background.id, None, None)?;
        self.level.draw(interpolation, &mut self.renderer)?;
        self.renderer.present();
        Ok(())
    }

    fn game_quit(&self) -> bool {
        self.input_manager.game_quit() || self.input_manager.is_key_down(Keycode::Escape)
    }
}
<commit_msg>use show to draw background as a scene<commit_after>mod drawable;
mod level;
mod shape;

use self::level::Level;
use self::drawable::GameRenderer;

use errors::*;
use moho::input_manager::InputManager;
use moho::resource_manager::{ResourceManager, Texture};
use moho::timer::Timer;
use moho::MohoEngine;
use sdl2::keyboard::Keycode;

use std::time::Duration;

pub struct MasterSmasher<E: MohoEngine> {
    level: Level,
    background: Texture,
    input_manager: InputManager<E::EventPump>,
    renderer: ResourceManager<E::Renderer>,
}

impl<E: MohoEngine> MasterSmasher<E> {
    pub fn new(mut renderer: ResourceManager<E::Renderer>,
               input_manager: InputManager<E::EventPump>)
               -> Result<Self> {
        let background = renderer.load_texture("resources/background_game.png")?;
        let window_size = renderer.output_size()?;
        renderer.wrap_coords = Some(window_size);
        let level = Level::load("levels/level_1.lvl", window_size, &renderer)?;
        Ok(MasterSmasher {
               level: level,
               background: background,
               input_manager: input_manager,
               renderer: renderer,
           })
    }

    pub fn run(&mut self) -> Result<()> {
        const GAME_SPEED: u32 = 60;
        const MAX_SKIP: u32 = 10;
        let update_duration = Duration::new(0, 1000000000 / GAME_SPEED);
        let mut timer = Timer::new();
        let mut delta: Duration = Default::default();
        while !self.game_quit() {
            let game_time = timer.update();
            delta += game_time.since_update;
            let mut loops: u32 = 0;
            while delta >= update_duration && loops < MAX_SKIP {
                self.input_manager.update();
                if self.game_quit() {
                    break;
                }
                self.update();
                delta -= update_duration;
                loops += 1;
            }
            if self.game_quit() {
                break;
            }
            self.level.animate(game_time.since_update);
            let interpolation = delta.subsec_nanos() as f64 / update_duration.subsec_nanos() as f64;
            self.draw(interpolation)?;
        }
        Ok(())
    }

    fn update(&mut self) {
        self.level.update(&self.input_manager);
    }

    fn draw(&mut self, interpolation: f64) -> Result<()> {
        self.renderer.clear();
        self.renderer.show(&self.background)?;
        self.level.draw(interpolation, &mut self.renderer)?;
        self.renderer.present();
        Ok(())
    }

    fn game_quit(&self) -> bool {
        self.input_manager.game_quit() || self.input_manager.is_key_down(Keycode::Escape)
    }
}
<|endoftext|>


<commit_before>use std::sync::{RwLock, RwLockWriteGuard};
use std::error::Error;

use iron::prelude::*;
use iron::status;
use iron::{AfterMiddleware, typemap};
use iron::modifier::Modifier;
use plugin::Plugin as PluginFor;
use iron::headers::ContentType;

use handlebars::{Handlebars, TemplateRenderError};
#[cfg(not(feature = "serde_type"))]
use serialize::json::{ToJson, Json};
#[cfg(feature = "serde_type")]
use serde::ser::Serialize as ToJson;
#[cfg(feature = "serde_type")]
use serde_json::value::{self, Value as Json};

use source::{Source, SourceError};

#[derive(Clone)]
pub struct Template {
    name: Option<String>,
    content: Option<String>,
    value: Json,
}

#[cfg(not(feature = "serde_type"))]
impl Template {
    /// render some template from pre-registered templates
    pub fn new<T: ToJson>(name: &str, value: T) -> Template {
        Template {
            name: Some(name.to_string()),
            value: value.to_json(),
            content: None,
        }
    }

    /// render some template with temporary template string
    pub fn with<T: ToJson>(content: &str, value: T) -> Template {
        Template {
            name: None,
            value: value.to_json(),
            content: Some(content.to_string()),
        }
    }
}

#[cfg(feature = "serde_type")]
impl Template {
    /// render some template from pre-registered templates
    pub fn new<T: ToJson>(name: &str, value: T) -> Template {
        Template {
            name: Some(name.to_string()),
            value: value::to_value(&value),
            content: None,
        }
    }

    /// render some template with temporary template string
    pub fn with<T: ToJson>(content: &str, value: T) -> Template {
        Template {
            name: None,
            value: value::to_value(&value),
            content: Some(content.to_string()),
        }
    }
}

pub struct HandlebarsEngine {
    pub sources: Vec<Box<Source + Send + Sync>>,
    pub registry: RwLock<Box<Handlebars>>,
}

impl typemap::Key for HandlebarsEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<HandlebarsEngine>(self);
    }
}

impl PluginFor<Response> for HandlebarsEngine {
    type Error = ();

    fn eval(resp: &mut Response) -> Result<Template, ()> {
        match resp.extensions.get::<HandlebarsEngine>() {
            Some(t) => Ok(t.clone()),
            None => Err(()),
        }
    }
}

impl HandlebarsEngine {
    pub fn new() -> HandlebarsEngine {
        HandlebarsEngine {
            sources: Vec::new(),
            registry: RwLock::new(Box::new(Handlebars::new())),
        }
    }

    pub fn from(reg: Handlebars) -> HandlebarsEngine {
        HandlebarsEngine {
            sources: Vec::new(),
            registry: RwLock::new(Box::new(reg)),
        }
    }

    pub fn add(&mut self, source: Box<Source + Send + Sync>) {
        self.sources.push(source);
    }

    pub fn reload(&self) -> Result<(), SourceError> {
        let mut hbs = self.handlebars_mut();
        hbs.clear_templates();
        for s in self.sources.iter() {
            try!(s.load(&mut hbs))
        }
        Ok(())
    }

    pub fn handlebars_mut(&self) -> RwLockWriteGuard<Box<Handlebars>> {
        self.registry.write().unwrap()
    }
}

impl AfterMiddleware for HandlebarsEngine {
    fn after(&self, _: &mut Request, mut resp: Response) -> IronResult<Response> {
        let page_wrapper = resp.extensions
                               .remove::<HandlebarsEngine>()
                               .and_then(|h| {
                                   let hbs = self.registry.read().unwrap();
                                   if let Some(ref name) = h.name {
                                       return Some(hbs.render(name, &h.value)
                                                      .map_err(TemplateRenderError::from));
                                   } else if let Some(ref content) = h.content {
                                       return Some(hbs.template_render(content, &h.value));
                                   } else {
                                       unreachable!();
                                   }
                               });

        match page_wrapper {
            Some(page_result) => {
                match page_result {
                    Ok(page) => {
                        if !resp.headers.has::<ContentType>() {
                            resp.headers.set(ContentType::html());
                        }
                        resp.set_mut(page);
                        Ok(resp)
                    }
                    Err(e) => {
                        info!("{}", e.description());
                        Err(IronError::new(e, status::InternalServerError))
                    }
                }
            }
            None => Ok(resp),
        }
    }

    fn catch(&self, req: &mut Request, mut err: IronError) -> IronResult<Response> {
        err.response = try!(self.after(req, err.response));
        Err(err)
    }
}

#[cfg(test)]
mod test {
    use std::collections::BTreeMap;
    use iron::prelude::*;
    use middleware::*;
    use handlebars::{Handlebars, RenderError, RenderContext, Helper};

    fn hello_world() -> IronResult<Response> {
        let resp = Response::new();

        let mut data = BTreeMap::new();
        data.insert("title".to_owned(), "Handlebars on Iron".to_owned());

        Ok(resp.set(Template::new("index", data)))
    }

    fn hello_world2() -> IronResult<Response> {
        let resp = Response::new();

        let mut data = BTreeMap::new();
        data.insert("title".to_owned(), "Handlebars on Iron".to_owned());

        Ok(resp.set(Template::with("{{title}}", data)))
    }

    #[test]
    #[cfg(not(feature = "serde_type"))]
    fn test_resp_set() {
        let mut resp = hello_world().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.name.unwrap(), "index".to_string());
                assert_eq!(h.value
                            .as_object()
                            .unwrap()
                            .get(&"title".to_string())
                            .unwrap()
                            .as_string()
                            .unwrap(),
                           "Handlebars on Iron");
            }
            _ => panic!("template expected"),
        }
    }

    #[test]
    #[cfg(feature = "serde_type")]
    fn test_resp_set() {
        let mut resp = hello_world().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.name.unwrap(), "index".to_string());
                assert_eq!(h.value
                            .as_object()
                            .unwrap()
                            .get(&"title".to_string())
                            .unwrap()
                            .as_str()
                            .unwrap(),
                           "Handlebars on Iron");
            }
            _ => panic!("template expected"),
        }
    }

    #[test]
    #[cfg(not(feature = "serde_type"))]
    fn test_resp_set2() {
        let mut resp = hello_world2().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.content.unwrap(), "{{title}}".to_string());
                assert_eq!(h.value
                            .as_object()
                            .unwrap()
                            .get(&"title".to_string())
                            .unwrap()
                            .as_string()
                            .unwrap(),
                           "Handlebars on Iron");
            }
            _ => panic!("template expected"),
        }
    }

    #[test]
    #[cfg(feature = "serde_type")]
    fn test_resp_set2() {
        let mut resp = hello_world2().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.content.unwrap(), "{{title}}".to_string());
                assert_eq!(h.value
                            .as_object()
                            .unwrap()
                            .get(&"title".to_string())
                            .unwrap()
                            .as_str()
                            .unwrap(),
                           "Handlebars on Iron");
            }
            _ => panic!("template expected"),
        }
    }

    #[test]
    fn test_register_helper() {
        let hbs = HandlebarsEngine::new();
        let mut reg = hbs.handlebars_mut();
        reg.register_helper("ignore",
                            Box::new(|_: &Helper,
                                      _: &Handlebars,
                                      _: &mut RenderContext|
                                      -> Result<(), RenderError> {
                                Ok(())
                            }));
    }
}
<commit_msg>(doc) add some inline docs<commit_after>use std::sync::{RwLock, RwLockWriteGuard};
use std::error::Error;

use iron::prelude::*;
use iron::status;
use iron::{AfterMiddleware, typemap};
use iron::modifier::Modifier;
use plugin::Plugin as PluginFor;
use iron::headers::ContentType;

use handlebars::{Handlebars, TemplateRenderError};
#[cfg(not(feature = "serde_type"))]
use serialize::json::{ToJson, Json};
#[cfg(feature = "serde_type")]
use serde::ser::Serialize as ToJson;
#[cfg(feature = "serde_type")]
use serde_json::value::{self, Value as Json};

use source::{Source, SourceError};

#[derive(Clone)]
pub struct Template {
    name: Option<String>,
    content: Option<String>,
    value: Json,
}

#[cfg(not(feature = "serde_type"))]
impl Template {
    /// render some template from pre-registered templates
    pub fn new<T: ToJson>(name: &str, value: T) -> Template {
        Template {
            name: Some(name.to_string()),
            value: value.to_json(),
            content: None,
        }
    }

    /// render some template with temporary template string
    pub fn with<T: ToJson>(content: &str, value: T) -> Template {
        Template {
            name: None,
            value: value.to_json(),
            content: Some(content.to_string()),
        }
    }
}

#[cfg(feature = "serde_type")]
impl Template {
    /// render some template from pre-registered templates
    pub fn new<T: ToJson>(name: &str, value: T) -> Template {
        Template {
            name: Some(name.to_string()),
            value: value::to_value(&value),
            content: None,
        }
    }

    /// render some template with temporary template string
    pub fn with<T: ToJson>(content: &str, value: T) -> Template {
        Template {
            name: None,
            value: value::to_value(&value),
            content: Some(content.to_string()),
        }
    }
}

/// The handlebars template engine
pub struct HandlebarsEngine {
    pub sources: Vec<Box<Source + Send + Sync>>,
    pub registry: RwLock<Box<Handlebars>>,
}

impl typemap::Key for HandlebarsEngine {
    type Value = Template;
}

impl Modifier<Response> for Template {
    fn modify(self, resp: &mut Response) {
        resp.extensions.insert::<HandlebarsEngine>(self);
    }
}

impl PluginFor<Response> for HandlebarsEngine {
    type Error = ();

    fn eval(resp: &mut Response) -> Result<Template, ()> {
        match resp.extensions.get::<HandlebarsEngine>() {
            Some(t) => Ok(t.clone()),
            None => Err(()),
        }
    }
}

impl HandlebarsEngine {
    /// create a handlebars template engine
    pub fn new() -> HandlebarsEngine {
        HandlebarsEngine {
            sources: Vec::new(),
            registry: RwLock::new(Box::new(Handlebars::new())),
        }
    }

    /// create a handlebars template engine from existed handlebars registry
    pub fn from(reg: Handlebars) -> HandlebarsEngine {
        HandlebarsEngine {
            sources: Vec::new(),
            registry: RwLock::new(Box::new(reg)),
        }
    }

    /// add a template source
    pub fn add(&mut self, source: Box<Source + Send + Sync>) {
        self.sources.push(source);
    }

    /// load template from registered sources
    pub fn reload(&self) -> Result<(), SourceError> {
        let mut hbs = self.handlebars_mut();
        hbs.clear_templates();
        for s in self.sources.iter() {
            try!(s.load(&mut hbs))
        }
        Ok(())
    }

    /// access internal handlebars registry, useful to register custom helpers
    pub fn handlebars_mut(&self) -> RwLockWriteGuard<Box<Handlebars>> {
        self.registry.write().unwrap()
    }
}

impl AfterMiddleware for HandlebarsEngine {
    fn after(&self, _: &mut Request, mut resp: Response) -> IronResult<Response> {
        let page_wrapper = resp.extensions
                               .remove::<HandlebarsEngine>()
                               .and_then(|h| {
                                   let hbs = self.registry.read().unwrap();
                                   if let Some(ref name) = h.name {
                                       return Some(hbs.render(name, &h.value)
                                                      .map_err(TemplateRenderError::from));
                                   } else if let Some(ref content) = h.content {
                                       return Some(hbs.template_render(content, &h.value));
                                   } else {
                                       unreachable!();
                                   }
                               });

        match page_wrapper {
            Some(page_result) => {
                match page_result {
                    Ok(page) => {
                        if !resp.headers.has::<ContentType>() {
                            resp.headers.set(ContentType::html());
                        }
                        resp.set_mut(page);
                        Ok(resp)
                    }
                    Err(e) => {
                        info!("{}", e.description());
                        Err(IronError::new(e, status::InternalServerError))
                    }
                }
            }
            None => Ok(resp),
        }
    }

    fn catch(&self, req: &mut Request, mut err: IronError) -> IronResult<Response> {
        err.response = try!(self.after(req, err.response));
        Err(err)
    }
}

#[cfg(test)]
mod test {
    use std::collections::BTreeMap;
    use iron::prelude::*;
    use middleware::*;
    use handlebars::{Handlebars, RenderError, RenderContext, Helper};

    fn hello_world() -> IronResult<Response> {
        let resp = Response::new();

        let mut data = BTreeMap::new();
        data.insert("title".to_owned(), "Handlebars on Iron".to_owned());

        Ok(resp.set(Template::new("index", data)))
    }

    fn hello_world2() -> IronResult<Response> {
        let resp = Response::new();

        let mut data = BTreeMap::new();
        data.insert("title".to_owned(), "Handlebars on Iron".to_owned());

        Ok(resp.set(Template::with("{{title}}", data)))
    }

    #[test]
    #[cfg(not(feature = "serde_type"))]
    fn test_resp_set() {
        let mut resp = hello_world().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.name.unwrap(), "index".to_string());
                assert_eq!(h.value
                            .as_object()
                            .unwrap()
                            .get(&"title".to_string())
                            .unwrap()
                            .as_string()
                            .unwrap(),
                           "Handlebars on Iron");
            }
            _ => panic!("template expected"),
        }
    }

    #[test]
    #[cfg(feature = "serde_type")]
    fn test_resp_set() {
        let mut resp = hello_world().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.name.unwrap(), "index".to_string());
                assert_eq!(h.value
                            .as_object()
                            .unwrap()
                            .get(&"title".to_string())
                            .unwrap()
                            .as_str()
                            .unwrap(),
                           "Handlebars on Iron");
            }
            _ => panic!("template expected"),
        }
    }

    #[test]
    #[cfg(not(feature = "serde_type"))]
    fn test_resp_set2() {
        let mut resp = hello_world2().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.content.unwrap(), "{{title}}".to_string());
                assert_eq!(h.value
                            .as_object()
                            .unwrap()
                            .get(&"title".to_string())
                            .unwrap()
                            .as_string()
                            .unwrap(),
                           "Handlebars on Iron");
            }
            _ => panic!("template expected"),
        }
    }

    #[test]
    #[cfg(feature = "serde_type")]
    fn test_resp_set2() {
        let mut resp = hello_world2().ok().expect("response expected");

        // use response plugin to retrieve a cloned template for testing
        match resp.get::<HandlebarsEngine>() {
            Ok(h) => {
                assert_eq!(h.content.unwrap(), "{{title}}".to_string());
                assert_eq!(h.value
                            .as_object()
                            .unwrap()
                            .get(&"title".to_string())
                            .unwrap()
                            .as_str()
                            .unwrap(),
                           "Handlebars on Iron");
            }
            _ => panic!("template expected"),
        }
    }

    #[test]
    fn test_register_helper() {
        let hbs = HandlebarsEngine::new();
        let mut reg = hbs.handlebars_mut();
        reg.register_helper("ignore",
                            Box::new(|_: &Helper,
                                      _: &Handlebars,
                                      _: &mut RenderContext|
                                      -> Result<(), RenderError> {
                                Ok(())
                            }));
    }
}
<|endoftext|>


<commit_before>type LineNumber = usize;

struct Line {
    sector: disk::Sector,
    data: Box<[u8]>,
    dirty: bool,
    flush_dependencies: Vec<LineNumber>,
}

impl Line {
    fn reset(&mut self) {
        // The cache line starts out as clean...
        self.dirty = false;
        // ...and hence has no dependencies.
        self.flush_dependencies.clear();
    }
}

struct WriteQuery<'a> {
    sector: disk::Sector,
    data: &'a [u8],
}

struct Cached<D> {
    disk: D,
    cache_tracker: plru::DynamicCache,
    line_map: HashMap<disk::Sector, LineNumber>,
    lines: Vec<[Line]>,
}

impl<D: Disk> Cached<D> {
    fn alloc_line(&mut self) -> LineNumber {
        // Test if the cache is filled.
        if self.lines.len() < self.cache_tracker.len() {
            // The cache is not filled, so we don't need to replace any cache line, we can simply
            // push.
            self.lines.push(Line {
                sector: sector,
                data: vec![0; self.disk.sector_size()],
                dirty: false,
                flush_dependencies: Vec::new(),
            });

            self.lines.len() - 1
        } else {
            // Find a candidate for replacement.
            let line_number = self.cache_tracker.replace();

            // Flush it to the disk before throwing the data away.
            self.flush(line_number);

            // Remove the old sector from the cache line map.
            let line = &mut self.lines[line_number];
            self.line_map.remove(line.sector);

            // Reset the cache line.
            line.reset();

            line_number
        }
    }

    fn fetch_fresh(&mut self, sector: disk::Sector) -> Result<&mut Line, disk::Error> {
        // Allocate a new cache line.
        let line_number = self.alloc_line();
        let line = &mut self.lines[line_number];

        // Read the sector from the disk.
        self.disk.read(sector, &mut line.data)?;

        // Update the sector number.
        line.sector = sector;

        // Update the cache line map with the new line.
        self.line_map.insert(sector, line_number);
    }

    fn write(&mut self, write: WriteQuery) -> LineNumber {
        // Allocate a new cache line.
        let line_number = self.alloc_line();
        let line = &mut self.lines[line_number];

        // Copy the data into the freshly allocated cache line.
        line.data.copy_from_slice(data);

        // Update the sector number.
        line.sector = sector;

        // Update the cache line map with the new line.
        self.line_map.insert(sector, line_number);

        line
    }

    fn write_seq<I: Iterator<Item = WriteQuery>>(&mut self, writes: I) {
        // Execute the first query and store the number of the cache line in which it is written.
        let mut prev_line_number = self.write(writes.next().unwrap());
        // Execute the rest of the queries.
        for query in writes {
            // Execute the query.
            let line_number = self.write(query);
            // Push the previous query as a dependency on the write.
            self.lines[line_number].flush_dependencies.push(prev_line_number);

            // Update the previous line number.
            prev_line_number = line_number;
        }
    }

    fn fetch(&mut self, sector: disk::Sector) -> Result<&mut Line, disk::Error> {
        if let Some(line) = self.line_map.get_mut(sector) {
            self.cache_tracker.touch(line);
            Ok(&mut self.lines[line])
        } else {
            self.fetch_fresh(sector)
        }
    }

    fn flush(&mut self, line: LineNumber) -> Result<(), disk::Error> {
        let line = &mut self.lines[line];

        for i in line.flush_dependencies {
            self.flush(i)?;
        }

        if line.dirty {
            self.disk.write(line.sector, 0, &line.data)?;
            line.dirty = false;
        }
    }
}
<commit_msg>Make sure the cache line is marked dirty after writes.<commit_after>type LineNumber = usize;

struct Line {
    sector: disk::Sector,
    data: Box<[u8]>,
    dirty: bool,
    flush_dependencies: Vec<LineNumber>,
}

impl Line {
    fn reset(&mut self) {
        // The cache line starts out as clean...
        self.dirty = false;
        // ...and hence has no dependencies.
        self.flush_dependencies.clear();
    }
}

struct WriteQuery<'a> {
    sector: disk::Sector,
    data: &'a [u8],
}

struct Cached<D> {
    disk: D,
    cache_tracker: plru::DynamicCache,
    line_map: RwLock<HashMap<disk::Sector, LineNumber>>,
    lines: RwLock<Vec<[RwLock<Line>]>>,
}

impl<D: Disk> Cached<D> {
    fn alloc_line(&mut self) -> LineNumber {
        // Test if the cache is filled.
        if self.lines.len() < self.cache_tracker.len() {
            // The cache is not filled, so we don't need to replace any cache line, we can simply
            // push.
            self.lines.push(Line {
                sector: sector,
                data: vec![0; self.disk.sector_size()],
                dirty: false,
                flush_dependencies: Vec::new(),
            });

            self.lines.len() - 1
        } else {
            // Find a candidate for replacement.
            let line_number = self.cache_tracker.replace();

            // Flush it to the disk before throwing the data away.
            self.flush(line_number);

            // Remove the old sector from the cache line map.
            let line = &mut self.lines[line_number];
            self.line_map.remove(line.sector);

            // Reset the cache line.
            line.reset();

            line_number
        }
    }

    fn fetch_fresh(&mut self, sector: disk::Sector) -> Result<&mut Line, disk::Error> {
        // Allocate a new cache line.
        let line_number = self.alloc_line();
        let line = &mut self.lines[line_number];

        // Read the sector from the disk.
        self.disk.read(sector, &mut line.data)?;

        // Update the sector number.
        line.sector = sector;

        // Update the cache line map with the new line.
        self.line_map.insert(sector, line_number);
    }

    fn write(&mut self, write: WriteQuery) -> LineNumber {
        // Allocate a new cache line.
        let line_number = self.alloc_line();
        let line = &mut self.lines[line_number];

        // Copy the data into the freshly allocated cache line.
        line.data.copy_from_slice(data);

        // Update the sector number.
        line.sector = sector;
        // Mark dirty.
        line.dirty = true;

        // Update the cache line map with the new line.
        self.line_map.insert(sector, line_number);

        line
    }

    fn write_seq<I: Iterator<Item = WriteQuery>>(&mut self, writes: I) {
        // Execute the first query and store the number of the cache line in which it is written.
        let mut prev_line_number = self.write(writes.next().unwrap());
        // Execute the rest of the queries.
        for query in writes {
            // Execute the query.
            let line_number = self.write(query);
            // Push the previous query as a dependency on the write.
            self.lines[line_number].flush_dependencies.push(prev_line_number);

            // Update the previous line number.
            prev_line_number = line_number;
        }
    }

    fn fetch(&mut self, sector: disk::Sector) -> Result<&mut Line, disk::Error> {
        if let Some(line) = self.line_map.get_mut(sector) {
            self.cache_tracker.touch(line);
            Ok(&mut self.lines[line])
        } else {
            self.fetch_fresh(sector)
        }
    }

    fn flush(&mut self, line: LineNumber) -> Result<(), disk::Error> {
        let line = &mut self.lines[line];

        for i in line.flush_dependencies {
            self.flush(i)?;
        }

        if line.dirty {
            self.disk.write(line.sector, 0, &line.data)?;
            line.dirty = false;
        }
    }
}
<|endoftext|>


<commit_before>// A unit struct
struct Nil;

// A tuple struct
struct Pair(i32, f32);

// A struct with two fields
struct Point {
    x: f32,
    y: f32,
}

// Structs can be reused as fields of another struct
#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn main() {
    // Instantiate a `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // Access the fields of the point
    println!("point coordinates: ({}, {})", point.x, point.y);

    // Destructure the point using a `let` binding
    let Point { x: my_x, y: my_y } = point;

    let _rectangle = Rectangle {
        // struct instantiation is an expression too
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };

    // Instantiate a unit struct
    let _nil = Nil;

    // Instantiate a tuple struct
    let pair = Pair(1, 0.1);

    // Destructure a tuple struct
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);
}
<commit_msg>implement rect_area for Activity<commit_after>// src: https://rustbyexample.com/custom_types/structs.html
// ^ I keep forgetting these, but it's obvious where the code is from!

// A unit struct
struct Nil;

// A tuple struct
struct Pair(i32, f32);

// Structs can be reused as fields of another struct
// and order doesn't matter!(aka forward declaration not needed)
#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

// A struct with two fields
struct Point {
    x: f32,
    y: f32,
}

fn main() {
    // Instantiate a `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // Access the fields of the point
    println!("point coordinates: ({}, {})", point.x, point.y);

    // Destructure the point using a `let` binding
    let Point { x: my_x, y: my_y } = point;

    let _rectangle = Rectangle {
        // struct instantiation is an expression too
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };

    // Instantiate a unit struct
    let _nil = Nil;

    // Instantiate a tuple struct
    let pair = Pair(1, 0.1);

    // Destructure a tuple struct
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);
    println!("area={}", rect_area(&_rectangle));
    let r=Rectangle{
        p1: Point{x:15_f32,y:10_f32},
        p2: Point{x:50_f32,y:27.0}};
    println!("area={}", rect_area(&r));
    assert_eq!(rect_area(&r), 595.0);

    let r1=Rectangle{
        p1: Point{x:48_f32,y:9_f32},
        p2: Point{x:14_f32,y:27.0}};
    println!("area={}", rect_area(&r1));
    assert_eq!(rect_area(&r1), 612.0);
    let r1_2=Rectangle{
        p1: Point{x:14_f32,y:9_f32},
        p2: Point{x:48_f32,y:27.0}};
    assert_eq!(rect_area(&r1_2), rect_area(&r1));
}

fn rect_area(r: &Rectangle) -> f32
{
  let Rectangle{p1: Point{x,y}, p2: Point{x:x2,y:y2}} = *r;

  //src: http://www.mathopenref.com/coordrectareaperim.html
  let (width, height)= ( (y-y2).abs(), (x-x2).abs());

  width*height
}
<|endoftext|>


<commit_before>use EnumMap;
use Internal;

use core::iter::Enumerate;
use core::marker::PhantomData;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
/// #[macro_use]
/// extern crate enum_map_derive;
///
/// #[derive(EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     assert_eq!(map[Example::A], 3);
///     for (key, &value) in &map {
///         assert_eq!(match key {
///             Example::A => 3,
///             _ => 0,
///         }, value);
///     }
/// }
/// ```
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: Internal<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }
}

impl<'a, K: Internal<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator.next_back().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }
}

impl<'a, K: Internal<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: Internal<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
/// #[macro_use]
/// extern crate enum_map_derive;
///
/// #[derive(Debug, EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     for (_, value) in &mut map {
///         *value += 1;
///     }
///     assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// }
/// ```
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: Internal<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }
}

impl<'a, K: Internal<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator.next_back().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }
}

impl<'a, K: Internal<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: Internal<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}
<commit_msg>Remove enum_map_derive from examples<commit_after>use EnumMap;
use Internal;

use core::iter::Enumerate;
use core::marker::PhantomData;
use core::slice;

/// Immutable enum map iterator
///
/// This struct is created by `iter` method or `into_iter` on a reference
/// to `EnumMap`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
///
/// #[derive(EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     assert_eq!(map[Example::A], 3);
///     for (key, &value) in &map {
///         assert_eq!(match key {
///             Example::A => 3,
///             _ => 0,
///         }, value);
///     }
/// }
/// ```
pub struct Iter<'a, K, V: 'a> {
    _phantom: PhantomData<K>,
    iterator: Enumerate<slice::Iter<'a, V>>,
}

impl<'a, K: Internal<V>, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }
}

impl<'a, K: Internal<V>, V> DoubleEndedIterator for Iter<'a, K, V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator.next_back().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }
}

impl<'a, K: Internal<V>, V> ExactSizeIterator for Iter<'a, K, V> {}

impl<'a, K: Internal<V>, V> IntoIterator for &'a EnumMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            _phantom: PhantomData,
            iterator: self.as_slice().iter().enumerate(),
        }
    }
}

/// Mutable map iterator
///
/// This struct is created by `iter_mut` method or `into_iter` on a mutable
/// reference to `EnumMap`.
///
/// # Examples
///
/// ```
/// #[macro_use]
/// extern crate enum_map;
///
/// #[derive(Debug, EnumMap)]
/// enum Example {
///     A,
///     B,
///     C,
/// }
///
/// fn main() {
///     let mut map = enum_map! { Example::A => 3, _ => 0 };
///     for (_, value) in &mut map {
///         *value += 1;
///     }
///     assert_eq!(map, enum_map! { Example::A => 4, _ => 1 });
/// }
/// ```
pub struct IterMut<'a, K, V: 'a> {
    _phantom: PhantomData<K>,
    iterator: Enumerate<slice::IterMut<'a, V>>,
}

impl<'a, K: Internal<V>, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);
    fn next(&mut self) -> Option<Self::Item> {
        self.iterator.next().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iterator.size_hint()
    }
}

impl<'a, K: Internal<V>, V> DoubleEndedIterator for IterMut<'a, K, V> {
    fn next_back(&mut self) -> Option<Self::Item> {
        self.iterator.next_back().map(|(index, item)| {
            (K::from_usize(index), item)
        })
    }
}

impl<'a, K: Internal<V>, V> ExactSizeIterator for IterMut<'a, K, V> {}

impl<'a, K: Internal<V>, V> IntoIterator for &'a mut EnumMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            _phantom: PhantomData,
            iterator: self.as_mut_slice().iter_mut().enumerate(),
        }
    }
}
<|endoftext|>


<commit_before>//! Syntax of the language.
//!
//! For now, most of the language is an EDSL describing an augmented GLSL with a few keywords.
use glsl::syntax::ExternalDeclaration;

/// Our shading language.
#[derive(Clone, Debug, PartialEq)]
pub enum Lang {
  /// An `export list_of_identifiers_` statement.
  Export(ExportList),
  /// A `from module import list of identifiers` statement.
  Import(ImportList),
  /// A GLSL external declaration.
  GLSL(ExternalDeclaration)
}

pub type Module = Vec<Lang>;

pub type Identifier = String;

/// An non-empty export list.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExportList {
  pub export_list: Vec<ModulePath>
}

/// A non-empty import list.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ImportList {
  pub module: ModulePath,
  pub list: Vec<ModulePath>
}

/// A module path is a list of module(s), representing a hierarchy.
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct ModulePath {
  pub path: Vec<ModuleName>
}

type ModuleName = String;
<commit_msg>Re-export the whole GLSL syntax.<commit_after>//! Syntax of the language.
//!
//! For now, most of the language is an EDSL describing an augmented GLSL with a few keywords.
pub use glsl::syntax::*;

/// Our shading language.
#[derive(Clone, Debug, PartialEq)]
pub enum Lang {
  /// An `export list_of_identifiers_` statement.
  Export(ExportList),
  /// A `from module import list of identifiers` statement.
  Import(ImportList),
  /// A GLSL external declaration.
  GLSL(ExternalDeclaration)
}

pub type Module = Vec<Lang>;

/// An non-empty export list.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ExportList {
  pub export_list: Vec<ModulePath>
}

/// A non-empty import list.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ImportList {
  pub module: ModulePath,
  pub list: Vec<ModulePath>
}

/// A module path is a list of module(s), representing a hierarchy.
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct ModulePath {
  pub path: Vec<ModuleName>
}

type ModuleName = String;
<|endoftext|>


<commit_before>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/

use game::{Move, Position, Side};
use nimstring;
use std::io;
use regex::{Regex, Captures};

#[derive(PartialEq)]
#[derive(Debug)]
enum Command {
    MakeMove(Move),
    UndoMove(Move),
    CalcNimstringValue,
}

impl Command {
    fn execute(self: &Command, pos: &mut Position) {
        match self {
            &Command::MakeMove(m) => { pos.make_move(m.x, m.y, m.side); },
            &Command::UndoMove(m) => { pos.undo_move(m.x, m.y, m.side); },
            &Command::CalcNimstringValue => {
                let (val, per_move) = nimstring::calc_value_with_moves(pos);
                println!("Position value is {}", val);
                for (m, v) in &per_move {
                    println!("{} {}", m, v);
                }
            }
        }
    }
}

fn parse_side(side_s: &str) -> Option<Side> {
    if side_s == "l" || side_s == "left" { Some(Side::Left) }
    else if side_s == "r" || side_s == "right" { Some(Side::Right) }
    else if side_s == "t" || side_s == "top" { Some(Side::Top) }
    else if side_s == "b" || side_s == "bottom" { Some(Side::Bottom) }
    else { None }
}

fn parse_move(caps: Captures) -> Result<Move, String> {
    let x = caps[1].parse::<usize>().unwrap();
    let y = caps[2].parse::<usize>().unwrap();
    let side_s = caps[3].to_lowercase();
    match parse_side(&side_s) {
        Some(side) => Ok(Move{x: x, y: y, side: side}),
        None => Err(format!("Unrecognised side: [{}]", side_s))
    }
}

fn parse_command(input: &str) -> Result<Command, String> {
    let move_re = Regex::new(r"^(\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = move_re.captures(input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::MakeMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    let undo_move_re = Regex::new(r"^[uU] (\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = undo_move_re.captures(input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::UndoMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    if "nv" == input.to_lowercase() {
        return Ok(Command::CalcNimstringValue);
    }
    Err("Unsupported command".to_string())
}

fn get_next_command() -> Command {
    loop {
        let mut input = String::new();
        if let Err(error) = io::stdin().read_line(&mut input) {
            println!("Error reading from standard input: {}", error);
            continue;
        }
        match parse_command(&input.trim()) {
            Ok(command) => return command,
            Err(error) => {
                println!("Cannot execute [{}]: {}", input, error);
            }
        }
    }
}

// Enter the main loop of the CLI
pub fn main_loop(width: usize, height: usize) {
    let mut pos = Position::new_game(width, height);
    loop {
        println!("{}", pos);
        let command = get_next_command();
        command.execute(&mut pos);
    }
}

#[cfg(test)]
mod tests {
    use game::*;
    use cli::*;

    #[test]
    fn parse_make_move_cmd() {
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 b").unwrap());
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 Bottom").unwrap());
    }

    #[test]
    fn parse_undo_move_cmd() {
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 l").unwrap());
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 Left").unwrap());
    }

    #[test]
    fn parse_nimstring_value_cmd() {
        assert_eq!(Command::CalcNimstringValue, parse_command("nv").unwrap());
    }
}
<commit_msg>Trim whitespace in error message too<commit_after>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/

use game::{Move, Position, Side};
use nimstring;
use std::io;
use regex::{Regex, Captures};

#[derive(PartialEq)]
#[derive(Debug)]
enum Command {
    MakeMove(Move),
    UndoMove(Move),
    CalcNimstringValue,
}

impl Command {
    fn execute(self: &Command, pos: &mut Position) {
        match self {
            &Command::MakeMove(m) => { pos.make_move(m.x, m.y, m.side); },
            &Command::UndoMove(m) => { pos.undo_move(m.x, m.y, m.side); },
            &Command::CalcNimstringValue => {
                let (val, per_move) = nimstring::calc_value_with_moves(pos);
                println!("Position value is {}", val);
                for (m, v) in &per_move {
                    println!("{} {}", m, v);
                }
            }
        }
    }
}

fn parse_side(side_s: &str) -> Option<Side> {
    if side_s == "l" || side_s == "left" { Some(Side::Left) }
    else if side_s == "r" || side_s == "right" { Some(Side::Right) }
    else if side_s == "t" || side_s == "top" { Some(Side::Top) }
    else if side_s == "b" || side_s == "bottom" { Some(Side::Bottom) }
    else { None }
}

fn parse_move(caps: Captures) -> Result<Move, String> {
    let x = caps[1].parse::<usize>().unwrap();
    let y = caps[2].parse::<usize>().unwrap();
    let side_s = caps[3].to_lowercase();
    match parse_side(&side_s) {
        Some(side) => Ok(Move{x: x, y: y, side: side}),
        None => Err(format!("Unrecognised side: [{}]", side_s))
    }
}

fn parse_command(input: &str) -> Result<Command, String> {
    let move_re = Regex::new(r"^(\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = move_re.captures(input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::MakeMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    let undo_move_re = Regex::new(r"^[uU] (\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = undo_move_re.captures(input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::UndoMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    if "nv" == input.to_lowercase() {
        return Ok(Command::CalcNimstringValue);
    }
    Err("Unsupported command".to_string())
}

fn get_next_command() -> Command {
    loop {
        let mut input = String::new();
        if let Err(error) = io::stdin().read_line(&mut input) {
            println!("Error reading from standard input: {}", error);
            continue;
        }
        let input = input.trim();
        match parse_command(&input) {
            Ok(command) => return command,
            Err(error) => {
                println!("Cannot execute [{}]: {}", input, error);
            }
        }
    }
}

// Enter the main loop of the CLI
pub fn main_loop(width: usize, height: usize) {
    let mut pos = Position::new_game(width, height);
    loop {
        println!("{}", pos);
        let command = get_next_command();
        command.execute(&mut pos);
    }
}

#[cfg(test)]
mod tests {
    use game::*;
    use cli::*;

    #[test]
    fn parse_make_move_cmd() {
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 b").unwrap());
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 Bottom").unwrap());
    }

    #[test]
    fn parse_undo_move_cmd() {
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 l").unwrap());
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 Left").unwrap());
    }

    #[test]
    fn parse_nimstring_value_cmd() {
        assert_eq!(Command::CalcNimstringValue, parse_command("nv").unwrap());
    }
}
<|endoftext|>


<commit_before>#![deny(missing_debug_implementations)]
#![deny(trivial_casts)]
#![deny(trivial_numeric_casts)]
#![deny(unused_import_braces)]
#![deny(variant_size_differences)]

#[cfg(feature = "diesel-support")]
#[macro_use]
extern crate diesel;

pub mod err;
pub mod local;
pub mod remote;

pub use err::{Error, Result};

/// Represents the type of a series.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum SeriesKind {
    /// TV episodes.
    Season,
    Movie,
    Special,
    OVA,
    ONA,
    Music,
}

/// Find the best matching item in `items` via `matcher` and return it if the maximum confidence is greater than `min_confidence`.
///
/// `min_confidence` should be a value between 0.0 and 1.0.
///
/// `matcher` is used to compare each item in `items`. When returning Some, its value should be between 0.0 and 1.0.
/// This value represents the "confidence" (or similarity) between the item and some other value.
///
/// If `matcher` returns a confidence greater than 0.99, that item will be immediately returned.
pub fn closest_match<I, T, F>(items: I, min_confidence: f32, matcher: F) -> Option<(usize, T)>
where
    I: IntoIterator<Item = T>,
    F: Fn(&T) -> Option<f32>,
{
    let mut max_score = 0.0;
    let mut best_match = None;

    for (i, item) in items.into_iter().enumerate() {
        let score = match matcher(&item) {
            Some(score) => score,
            None => continue,
        };

        if score > max_score {
            best_match = Some((i, item));

            if score > 0.99 {
                return best_match;
            }

            max_score = score;
        }
    }

    if max_score < min_confidence {
        return None;
    }

    best_match
}
<commit_msg>anime: Enable most pedantic clippy warnings<commit_after>#![warn(clippy::pedantic)]
#![allow(clippy::clippy::cast_possible_truncation)]
#![allow(clippy::inline_always)]
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::shadow_unrelated)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::map_err_ignore)]

#[cfg(feature = "diesel-support")]
#[macro_use]
extern crate diesel;

pub mod err;
pub mod local;
pub mod remote;

pub use err::{Error, Result};

/// Represents the type of a series.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum SeriesKind {
    /// TV episodes.
    Season,
    Movie,
    Special,
    OVA,
    ONA,
    Music,
}

/// Find the best matching item in `items` via `matcher` and return it if the maximum confidence is greater than `min_confidence`.
///
/// `min_confidence` should be a value between 0.0 and 1.0.
///
/// `matcher` is used to compare each item in `items`. When returning Some, its value should be between 0.0 and 1.0.
/// This value represents the "confidence" (or similarity) between the item and some other value.
///
/// If `matcher` returns a confidence greater than 0.99, that item will be immediately returned.
pub fn closest_match<I, T, F>(items: I, min_confidence: f32, matcher: F) -> Option<(usize, T)>
where
    I: IntoIterator<Item = T>,
    F: Fn(&T) -> Option<f32>,
{
    let mut max_score = 0.0;
    let mut best_match = None;

    for (i, item) in items.into_iter().enumerate() {
        let score = match matcher(&item) {
            Some(score) => score,
            None => continue,
        };

        if score > max_score {
            best_match = Some((i, item));

            if score > 0.99 {
                return best_match;
            }

            max_score = score;
        }
    }

    if max_score < min_confidence {
        return None;
    }

    best_match
}
<|endoftext|>


<commit_before>use crate::faker::http::raw::*;
use crate::locales::Data;
use crate::{Dummy, Fake, Faker};
use http;
use rand::Rng;

impl<L: Data> Dummy<RfcStatusCode<L>> for http::StatusCode {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &RfcStatusCode<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng(rng)
    }
}

impl<L: Data> Dummy<RfcStatusCode<L>> for String {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &RfcStatusCode<L>, rng: &mut R) -> Self {
        let code: http::StatusCode = Faker.fake_with_rng(rng);
        format!("{}", code)
    }
}

impl<L: Data> Dummy<ValidStatusCode<L>> for http::StatusCode {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &ValidStatusCode<L>, rng: &mut R) -> Self {
        let code: u16 = (100..600).fake_with_rng(rng);
        http::StatusCode::from_u16(code).unwrap()
    }
}

impl<L: Data> Dummy<ValidStatusCode<L>> for String {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &ValidStatusCode<L>, rng: &mut R) -> Self {
        let code: u16 = (100..600).fake_with_rng(rng);
        format!("{}", http::StatusCode::from_u16(code).unwrap())
    }
}
<commit_msg>cargo clippy<commit_after>use crate::faker::http::raw::*;
use crate::locales::Data;
use crate::{Dummy, Fake, Faker};
use rand::Rng;

impl<L: Data> Dummy<RfcStatusCode<L>> for http::StatusCode {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &RfcStatusCode<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng(rng)
    }
}

impl<L: Data> Dummy<RfcStatusCode<L>> for String {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &RfcStatusCode<L>, rng: &mut R) -> Self {
        let code: http::StatusCode = Faker.fake_with_rng(rng);
        format!("{}", code)
    }
}

impl<L: Data> Dummy<ValidStatusCode<L>> for http::StatusCode {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &ValidStatusCode<L>, rng: &mut R) -> Self {
        let code: u16 = (100..600).fake_with_rng(rng);
        http::StatusCode::from_u16(code).unwrap()
    }
}

impl<L: Data> Dummy<ValidStatusCode<L>> for String {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &ValidStatusCode<L>, rng: &mut R) -> Self {
        let code: u16 = (100..600).fake_with_rng(rng);
        format!("{}", http::StatusCode::from_u16(code).unwrap())
    }
}
<|endoftext|>