<commit_before>use {Event, WindowBuilder};

use cocoa::base::{id, NSUInteger, nil};
use cocoa::appkit::*;

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};

pub struct Window {
    context: id,
}

pub struct MonitorID;

pub fn get_available_monitors() -> Vec<MonitorID> {
    unimplemented!()
}

pub fn get_primary_monitor() -> MonitorID {
    unimplemented!()
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
       unimplemented!()
    }

    pub fn get_dimensions(&self) -> (uint, uint) {
        unimplemented!()
    }
}

impl Window {
    pub fn new(_builder: WindowBuilder) -> Result<Window, String> {

        let app = match Window::create_app() {
            Some(app) => app,
            None      => { return Err(format!("Couldn't create NSApplication")); },
        };
        let window = match Window::create_window(_builder.dimensions.unwrap_or((800, 600)), _builder.title.as_slice()) {
            Some(window) => window,
            None         => { return Err(format!("Couldn't create NSWindow")); },
        };
        let view = match Window::create_view(window) {
            Some(view) => view,
            None       => { return Err(format!("Couldn't create NSView")); },
        };

        let context = match Window::create_context(view) {
            Some(context) => context,
            None          => { return Err(format!("Couldn't create OpenGL context")); },
        };

        unsafe {
            app.activateIgnoringOtherApps_(true);
            window.makeKeyAndOrderFront_(nil);
        }

        let window = Window {
            context: context,
        };

        Ok(window)
    }

    fn create_app() -> Option<id> {
        unsafe {
            let app = NSApp();
            if app == nil {
                None
            } else {
                app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
                app.finishLaunching();
                Some(app)
            }
        }
    }

    fn create_window(dimensions: (uint, uint), title: &str) -> Option<id> {
        unsafe {
            let (width, height) = dimensions;
            let scr_frame = NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64));

            let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
                scr_frame,
                NSTitledWindowMask as NSUInteger | NSClosableWindowMask as NSUInteger | NSMiniaturizableWindowMask as NSUInteger,
                NSBackingStoreBuffered,
                false
            );

            if window == nil {
                None
            } else {
                let title = NSString::alloc(nil).init_str(title);
                window.setTitle_(title);
                window.center();
                Some(window)
            }
        }
    }

    fn create_view(window: id) -> Option<id> {
        unsafe {
            let view = NSView::alloc(nil).init();
            if view == nil {
                None
            } else {
                view.setWantsBestResolutionOpenGLSurface_(true);
                window.setContentView(view);
                Some(view)
            }
        }
    }

    fn create_context(view: id) -> Option<id> {
        unsafe {
            let attributes = [
                NSOpenGLPFADoubleBuffer as uint,
                NSOpenGLPFAClosestPolicy as uint,
                NSOpenGLPFAColorSize as uint, 24,
                NSOpenGLPFAAlphaSize as uint, 8,
                NSOpenGLPFADepthSize as uint, 24,
                NSOpenGLPFAStencilSize as uint, 8,
                0
            ];

            let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(attributes);
            if pixelformat == nil {
                return None;
            }

            let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil);
            if context == nil {
                None
            } else {
                context.setView_(view);
                Some(context)
            }
        }
    }

    pub fn is_closed(&self) -> bool {
        // TODO: remove fake implementation
        false
    }

    pub fn set_title(&self, _title: &str) {
        unimplemented!()
    }

    pub fn get_position(&self) -> Option<(int, int)> {
        unimplemented!()
    }

    pub fn set_position(&self, _x: int, _y: int) {
        unimplemented!()
    }

    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        unimplemented!()
    }

    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        unimplemented!()
    }

    pub fn set_inner_size(&self, _x: uint, _y: uint) {
        unimplemented!()
    }

    pub fn poll_events(&self) -> Vec<Event> {
        let mut events = Vec::new();

        loop {
            unsafe {
                use {MouseInput, Pressed, Released, LeftMouseButton, RightMouseButton};
                let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
                    NSAnyEventMask as u64,
                    NSDate::distantPast(nil),
                    NSDefaultRunLoopMode,
                    true);
                if event == nil { break; }

                match event.get_type() {
                    NSLeftMouseDown         => { events.push(MouseInput(Pressed, LeftMouseButton)); },
                    NSLeftMouseUp           => { events.push(MouseInput(Released, LeftMouseButton)); },
                    NSRightMouseDown        => { events.push(MouseInput(Pressed, RightMouseButton)); },
                    NSRightMouseUp          => { events.push(MouseInput(Released, RightMouseButton)); },
                    NSMouseMoved            => { },
                    NSKeyDown               => { },
                    NSKeyUp                 => { },
                    NSFlagsChanged          => { },
                    NSScrollWheel           => { },
                    NSOtherMouseDown        => { },
                    NSOtherMouseUp          => { },
                    NSOtherMouseDragged     => { },
                    _                       => { },
                }
            }
        }
        events
    }

    pub fn wait_events(&self) -> Vec<Event> {
        unsafe {
            let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
                NSAnyEventMask as u64,
                NSDate::distantFuture(nil),
                NSDefaultRunLoopMode,
                true);
            NSApp().sendEvent_(event);
            self.poll_events()
        }
    }

    pub unsafe fn make_current(&self) {
        self.context.makeCurrentContext();
    }

    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        let symbol_name: CFString = from_str(_addr).unwrap();
        let framework_name: CFString = from_str("com.apple.opengl").unwrap();
        let framework = unsafe {
            CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const ()
    }

    pub fn swap_buffers(&self) {
        unsafe { self.context.flushBuffer(); }
    }
}
<commit_msg>Fixed a space missing<commit_after>use {Event, WindowBuilder};

use cocoa::base::{id, NSUInteger, nil};
use cocoa::appkit::*;

use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};

pub struct Window {
    context: id,
}

pub struct MonitorID;

pub fn get_available_monitors() -> Vec<MonitorID> {
    unimplemented!()
}

pub fn get_primary_monitor() -> MonitorID {
    unimplemented!()
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        unimplemented!()
    }

    pub fn get_dimensions(&self) -> (uint, uint) {
        unimplemented!()
    }
}

impl Window {
    pub fn new(_builder: WindowBuilder) -> Result<Window, String> {

        let app = match Window::create_app() {
            Some(app) => app,
            None      => { return Err(format!("Couldn't create NSApplication")); },
        };
        let window = match Window::create_window(_builder.dimensions.unwrap_or((800, 600)), _builder.title.as_slice()) {
            Some(window) => window,
            None         => { return Err(format!("Couldn't create NSWindow")); },
        };
        let view = match Window::create_view(window) {
            Some(view) => view,
            None       => { return Err(format!("Couldn't create NSView")); },
        };

        let context = match Window::create_context(view) {
            Some(context) => context,
            None          => { return Err(format!("Couldn't create OpenGL context")); },
        };

        unsafe {
            app.activateIgnoringOtherApps_(true);
            window.makeKeyAndOrderFront_(nil);
        }

        let window = Window {
            context: context,
        };

        Ok(window)
    }

    fn create_app() -> Option<id> {
        unsafe {
            let app = NSApp();
            if app == nil {
                None
            } else {
                app.setActivationPolicy_(NSApplicationActivationPolicyRegular);
                app.finishLaunching();
                Some(app)
            }
        }
    }

    fn create_window(dimensions: (uint, uint), title: &str) -> Option<id> {
        unsafe {
            let (width, height) = dimensions;
            let scr_frame = NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64));

            let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
                scr_frame,
                NSTitledWindowMask as NSUInteger | NSClosableWindowMask as NSUInteger | NSMiniaturizableWindowMask as NSUInteger,
                NSBackingStoreBuffered,
                false
            );

            if window == nil {
                None
            } else {
                let title = NSString::alloc(nil).init_str(title);
                window.setTitle_(title);
                window.center();
                Some(window)
            }
        }
    }

    fn create_view(window: id) -> Option<id> {
        unsafe {
            let view = NSView::alloc(nil).init();
            if view == nil {
                None
            } else {
                view.setWantsBestResolutionOpenGLSurface_(true);
                window.setContentView(view);
                Some(view)
            }
        }
    }

    fn create_context(view: id) -> Option<id> {
        unsafe {
            let attributes = [
                NSOpenGLPFADoubleBuffer as uint,
                NSOpenGLPFAClosestPolicy as uint,
                NSOpenGLPFAColorSize as uint, 24,
                NSOpenGLPFAAlphaSize as uint, 8,
                NSOpenGLPFADepthSize as uint, 24,
                NSOpenGLPFAStencilSize as uint, 8,
                0
            ];

            let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(attributes);
            if pixelformat == nil {
                return None;
            }

            let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil);
            if context == nil {
                None
            } else {
                context.setView_(view);
                Some(context)
            }
        }
    }

    pub fn is_closed(&self) -> bool {
        // TODO: remove fake implementation
        false
    }

    pub fn set_title(&self, _title: &str) {
        unimplemented!()
    }

    pub fn get_position(&self) -> Option<(int, int)> {
        unimplemented!()
    }

    pub fn set_position(&self, _x: int, _y: int) {
        unimplemented!()
    }

    pub fn get_inner_size(&self) -> Option<(uint, uint)> {
        unimplemented!()
    }

    pub fn get_outer_size(&self) -> Option<(uint, uint)> {
        unimplemented!()
    }

    pub fn set_inner_size(&self, _x: uint, _y: uint) {
        unimplemented!()
    }

    pub fn poll_events(&self) -> Vec<Event> {
        let mut events = Vec::new();

        loop {
            unsafe {
                use {MouseInput, Pressed, Released, LeftMouseButton, RightMouseButton};
                let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
                    NSAnyEventMask as u64,
                    NSDate::distantPast(nil),
                    NSDefaultRunLoopMode,
                    true);
                if event == nil { break; }

                match event.get_type() {
                    NSLeftMouseDown         => { events.push(MouseInput(Pressed, LeftMouseButton)); },
                    NSLeftMouseUp           => { events.push(MouseInput(Released, LeftMouseButton)); },
                    NSRightMouseDown        => { events.push(MouseInput(Pressed, RightMouseButton)); },
                    NSRightMouseUp          => { events.push(MouseInput(Released, RightMouseButton)); },
                    NSMouseMoved            => { },
                    NSKeyDown               => { },
                    NSKeyUp                 => { },
                    NSFlagsChanged          => { },
                    NSScrollWheel           => { },
                    NSOtherMouseDown        => { },
                    NSOtherMouseUp          => { },
                    NSOtherMouseDragged     => { },
                    _                       => { },
                }
            }
        }
        events
    }

    pub fn wait_events(&self) -> Vec<Event> {
        unsafe {
            let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
                NSAnyEventMask as u64,
                NSDate::distantFuture(nil),
                NSDefaultRunLoopMode,
                true);
            NSApp().sendEvent_(event);
            self.poll_events()
        }
    }

    pub unsafe fn make_current(&self) {
        self.context.makeCurrentContext();
    }

    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        let symbol_name: CFString = from_str(_addr).unwrap();
        let framework_name: CFString = from_str("com.apple.opengl").unwrap();
        let framework = unsafe {
            CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef())
        };
        let symbol = unsafe {
            CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef())
        };
        symbol as *const ()
    }

    pub fn swap_buffers(&self) {
        unsafe { self.context.flushBuffer(); }
    }
}
<|endoftext|>


<commit_before>//! A palette for use with Objects

use serde;
use rustc_serialize; // needed for toml
use toml;

use std::fs::File;
use std::path::Path;
use std::error::Error;
use std::io::Read;

use std::collections::HashMap;
use std::iter::{repeat,FromIterator};

use kiss3d::scene::SceneNode;

use objects::ObjectID;

/// An RGB color
#[derive(Eq,PartialEq,Ord,PartialOrd,Hash,Copy,Clone)]
pub struct Color(pub u8,pub u8,pub u8);

/// Default colors to use, when no others are specified.
pub static DEFAULT_COLORS : [(u8, u8, u8); 11] = [
    ( 77, 175,  74), // Green
    (152,  78, 163), // Purple
    (255, 127,   0), // Orange
    (228,  26,  28), // Red
    ( 55, 126, 184), // Blue
    (166,  86,  40), // Brown
    (247, 129, 191), // Pink
    (153, 153, 153), // Gray
    (255, 255,  51), // Yellow
    (255, 255, 255), // White
    (  0,   0,   0), // Black
];

impl Color {
    fn to_floats(self) -> (f32, f32, f32) {
        let Color(r,g,b) = self;
        (
            (r as f32) / (u8::max_value() as f32),
            (g as f32) / (u8::max_value() as f32),
            (b as f32) / (u8::max_value() as f32),
        )
    }
}

/// A [bool] for keeping track of which part of the objectID should be used
#[derive(Debug,Eq,PartialEq,Ord,PartialOrd,Hash,Clone)]
#[derive(Serialize,Deserialize)]
#[derive(RustcDecodable,RustcEncodable)]
pub struct PartialIDer {
    /// Which sections of an ObjectID should be converted
    pub bools : Vec<bool>,
}

impl PartialIDer {
    /// New, with all set to given boolean value
    pub fn new(n : usize, value : bool) -> Self {
        PartialIDer {
            bools : repeat(value).take(n).collect(),
        }
    }

    /// Get the portion of an ID
    pub fn partial<'a>(&self, name: &'a ObjectID) -> Vec<&'a str> {
        let &ObjectID(ref names) = name;
        names.iter()
            .zip(self.bools.iter())
            .filter_map(|(n, &b)| if b {Some(&n[..])} else {None})
            .collect()
    }

    /// Get the portion of an ID
    pub fn as_id(&self, name: &ObjectID) -> ObjectID {
        let &ObjectID(ref names) = name;
        ObjectID(
            names
            .iter()
            .zip(self.bools.iter())
            .filter_map(|(n, &b)| if b {Some(n.clone())} else {None})
            .collect()
        )
    }

    /// Get a string representing the current state
    pub fn as_string(&self) -> String {
        let mut s = String::with_capacity(self.bools.len());
        let pieces : Vec<String> = self.bools.iter().enumerate().map(
            |(n, &b)| if b {format!("{}", (n+1) % 10)} else {String::from("_")}
        ).collect();
        s.extend(pieces.iter().map(|p| &p[0..1]));
        s
    }
}

/// A way to convert string names to colors
#[derive(Clone)]
pub struct Palette {
    default_colors : Vec<Color>,
    partials : PartialIDer,

    /// Mapping of names -> colors, when found. names not found will be given default colors.
    pub assigned : HashMap<ObjectID, Color>,
    next_color : usize
}

impl Palette {
    /// Set the color of an object to match what the palette says
    pub fn set_color(&mut self, name: &ObjectID, node: &mut SceneNode) {
        let (r, g, b) = self.get_color(name).to_floats();
        node.set_color(r, g, b);
    }

    /// Get the color for a particular ID (using partials mask)
    pub fn get_color(&mut self, name: &ObjectID) -> Color {
        let partial = self.partials.as_id(name);
        let (next_color, default_colors, assigned) =
            (&mut self.next_color, &self.default_colors, &mut self.assigned);
        let color = *assigned.entry(partial).or_insert_with(|| {
            let col = default_colors[*next_color];
            *next_color = (*next_color + 1) % default_colors.len();
            col
        });
        return color
    }

    /// Toggle whether or not to use a certain partial value
    pub fn toggle_partial(&mut self, n : usize){
        self.partials.bools[n] = !self.partials.bools[n];
        self.next_color = 0;
    }

    /// Check value of a certain partial
    pub fn get_partial(&mut self, n : usize) -> bool {
        self.partials.bools[n]
    }

    /// Check value of a certain partial
    pub fn set_partial(&mut self, n : usize, value : bool){
        self.partials.bools[n] = value;
        self.next_color = 0;
    }

    /// Check value of a certain partial
    pub fn set_all_partial(&mut self, value : bool){
        let n = self.partials.bools.len();
        for i in 0..n {
            self.partials.bools[i] = value;
        }
        self.next_color = 0;
    }

    /// Get a string like '_23____' for which parts of the ObjectID we are coloring with respect to
    pub fn partials_string(&self) -> String {
        self.partials.as_string()
    }

    /// Load from a file, using toml-rs and serialize
    pub fn load(path : &Path) -> Result<Self, Box<Error>> {
        let mut file : File = try!(File::open(path));
        let mut s = String::new();
        let _ = try!(file.read_to_string(&mut s));
        let mut parser = toml::Parser::new(s.as_ref());

        let parsed = parser.parse();
        let values = match parsed {
            Some(v) => v,
            None => {
                // We can unwrap here, becase parser.parse() == None means there were errors
                let err : Box<Error> = parser.errors.pop().unwrap().into();
                return Err(err)
            }
        };
        let table : toml::Value = toml::Value::Table(values);
        let mut decoder = toml::Decoder::new(table);
        let p = try!(rustc_serialize::Decodable::decode(&mut decoder));
        Ok(p)
    }
}

impl Default for Palette {
    fn default() -> Self {
        Palette {
            default_colors : FromIterator::from_iter(DEFAULT_COLORS.iter().map(
                |&(r,g,b)|{Color(r,g,b)}
            )),
            partials : PartialIDer::new(8, true),
            assigned : HashMap::new(),
            next_color : 0
        }
    }
}

#[derive(Serialize, RustcEncodable, Copy, Clone)]
struct AssignmentRef<'a> {
    names : &'a ObjectID,
    color : &'a Color
}

fn to_assignments<'a>(assigned : &'a HashMap<ObjectID, Color>) -> Vec<AssignmentRef<'a>> {
    assigned.into_iter().map(|(k, v)| {
        AssignmentRef{
            names : k,
            color : v
        }
    }).collect()
}

/// A reference to a palette, with minimal data, for serialization purposes
#[derive(Serialize, RustcEncodable, Clone)]
pub struct PaletteRef<'a> {
    defaults : &'a Vec<Color>,
    partials : &'a PartialIDer,
    assigned : Vec<AssignmentRef<'a>>
}

impl<'a> From<&'a Palette> for PaletteRef<'a> {
    fn from(palette: &'a Palette) -> Self {
        PaletteRef {
            defaults : &palette.default_colors,
            partials : &palette.partials,
            assigned : to_assignments(&palette.assigned),
        }
    }
}

#[derive(Deserialize, RustcDecodable, Clone)]
struct Assignment {
    names : ObjectID,
    color : Color
}

fn from_assignments(assigned : Vec<Assignment>) -> HashMap<ObjectID, Color> {
    assigned.into_iter().map(|a| {
        (a.names, a.color)
    }).collect()
}

/// A reference to a palette, with minimal data
#[derive(Deserialize, RustcDecodable, Clone)]
pub struct PaletteBasic {
    defaults : Vec<Color>,
    partials : PartialIDer,
    assigned : Option<Vec<Assignment>>,
    next_color : Option<usize>
}

impl From<PaletteBasic> for Palette {
    fn from(p : PaletteBasic) -> Self {
        Palette {
            default_colors : p.defaults,
            partials : p.partials,
            assigned : p.assigned.map(from_assignments).unwrap_or_default(),
            next_color : p.next_color.unwrap_or(0)
        }
    }
}

//TODO: add test for round-trip through toml and json

impl serde::Serialize for Color {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer {
        let &Color(r,g,b) = self;
        serde::Serialize::serialize(&(r,g,b), serializer)
    }
}

impl serde::Deserialize for Color {
    fn deserialize<D : serde::Deserializer>(deserializer: &mut D) -> Result<Self, D::Error> {
        let (r,g,b) = try!(serde::Deserialize::deserialize(deserializer));
        Ok(Color(r,g,b))
    }
}

impl rustc_serialize::Encodable for Color {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let &Color(r,g,b) = self;
        rustc_serialize::Encodable::encode(&(r,g,b), s)
    }
}

impl rustc_serialize::Decodable for Color {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let (r,g,b) = try!(rustc_serialize::Decodable::decode(d));
        Ok(Color(r,g,b))
    }
}

impl serde::Serialize for Palette {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer {
        PaletteRef::from(self).serialize(serializer)
    }
}

impl serde::Deserialize for Palette {
    fn deserialize<D : serde::Deserializer>(deserializer: &mut D) -> Result<Self, D::Error>  {
        let p = try!(PaletteBasic::deserialize(deserializer));
        Ok(Palette::from(p))
    }
}

impl rustc_serialize::Encodable for Palette {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        PaletteRef::from(self).encode(s)
    }
}

impl rustc_serialize::Decodable for Palette {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let p = try!(PaletteBasic::decode(d));
        Ok(Palette::from(p))
    }
}
<commit_msg>No longer panics when Key8 is pressed<commit_after>//! A palette for use with Objects

use serde;
use rustc_serialize; // needed for toml
use toml;

use std::fs::File;
use std::path::Path;
use std::error::Error;
use std::io::Read;

use std::collections::HashMap;
use std::iter::{repeat,FromIterator};

use kiss3d::scene::SceneNode;

use objects::ObjectID;

/// An RGB color
#[derive(Eq,PartialEq,Ord,PartialOrd,Hash,Copy,Clone)]
pub struct Color(pub u8,pub u8,pub u8);

/// Default colors to use, when no others are specified.
pub static DEFAULT_COLORS : [(u8, u8, u8); 11] = [
    ( 77, 175,  74), // Green
    (152,  78, 163), // Purple
    (255, 127,   0), // Orange
    (228,  26,  28), // Red
    ( 55, 126, 184), // Blue
    (166,  86,  40), // Brown
    (247, 129, 191), // Pink
    (153, 153, 153), // Gray
    (255, 255,  51), // Yellow
    (255, 255, 255), // White
    (  0,   0,   0), // Black
];

impl Color {
    fn to_floats(self) -> (f32, f32, f32) {
        let Color(r,g,b) = self;
        (
            (r as f32) / (u8::max_value() as f32),
            (g as f32) / (u8::max_value() as f32),
            (b as f32) / (u8::max_value() as f32),
        )
    }
}

/// A [bool] for keeping track of which part of the objectID should be used
#[derive(Debug,Eq,PartialEq,Ord,PartialOrd,Hash,Clone)]
#[derive(Serialize,Deserialize)]
#[derive(RustcDecodable,RustcEncodable)]
pub struct PartialIDer {
    /// Which sections of an ObjectID should be converted
    pub bools : Vec<bool>,
}

impl PartialIDer {
    /// New, with all set to given boolean value
    pub fn new(n : usize, value : bool) -> Self {
        PartialIDer {
            bools : repeat(value).take(n).collect(),
        }
    }

    /// Get the portion of an ID
    pub fn partial<'a>(&self, name: &'a ObjectID) -> Vec<&'a str> {
        let &ObjectID(ref names) = name;
        names.iter()
            .zip(self.bools.iter())
            .filter_map(|(n, &b)| if b {Some(&n[..])} else {None})
            .collect()
    }

    /// Get the portion of an ID
    pub fn as_id(&self, name: &ObjectID) -> ObjectID {
        let &ObjectID(ref names) = name;
        ObjectID(
            names
            .iter()
            .zip(self.bools.iter())
            .filter_map(|(n, &b)| if b {Some(n.clone())} else {None})
            .collect()
        )
    }

    /// Get a string representing the current state
    pub fn as_string(&self) -> String {
        let mut s = String::with_capacity(self.bools.len());
        let pieces : Vec<String> = self.bools.iter().enumerate().map(
            |(n, &b)| if b {format!("{}", (n+1) % 10)} else {String::from("_")}
        ).collect();
        s.extend(pieces.iter().map(|p| &p[0..1]));
        s
    }
}

/// A way to convert string names to colors
#[derive(Clone)]
pub struct Palette {
    default_colors : Vec<Color>,
    partials : PartialIDer,

    /// Mapping of names -> colors, when found. names not found will be given default colors.
    pub assigned : HashMap<ObjectID, Color>,
    next_color : usize
}

impl Palette {
    /// Set the color of an object to match what the palette says
    pub fn set_color(&mut self, name: &ObjectID, node: &mut SceneNode) {
        let (r, g, b) = self.get_color(name).to_floats();
        node.set_color(r, g, b);
    }

    /// Get the color for a particular ID (using partials mask)
    pub fn get_color(&mut self, name: &ObjectID) -> Color {
        let partial = self.partials.as_id(name);
        let (next_color, default_colors, assigned) =
            (&mut self.next_color, &self.default_colors, &mut self.assigned);
        let color = *assigned.entry(partial).or_insert_with(|| {
            let col = default_colors[*next_color];
            *next_color = (*next_color + 1) % default_colors.len();
            col
        });
        return color
    }

    /// Toggle whether or not to use a certain partial value
    pub fn toggle_partial(&mut self, n : usize){
        if n > self.partials.bools.len() {return;};
        self.partials.bools[n] = !self.partials.bools[n];
        self.next_color = 0;
    }

    /// Check value of a certain partial
    pub fn get_partial(&mut self, n : usize) -> bool {
        self.partials.bools[n]
    }

    /// Check value of a certain partial
    pub fn set_partial(&mut self, n : usize, value : bool){
        self.partials.bools[n] = value;
        self.next_color = 0;
    }

    /// Check value of a certain partial
    pub fn set_all_partial(&mut self, value : bool){
        let n = self.partials.bools.len();
        for i in 0..n {
            self.partials.bools[i] = value;
        }
        self.next_color = 0;
    }

    /// Get a string like '_23____' for which parts of the ObjectID we are coloring with respect to
    pub fn partials_string(&self) -> String {
        self.partials.as_string()
    }

    /// Load from a file, using toml-rs and serialize
    pub fn load(path : &Path) -> Result<Self, Box<Error>> {
        let mut file : File = try!(File::open(path));
        let mut s = String::new();
        let _ = try!(file.read_to_string(&mut s));
        let mut parser = toml::Parser::new(s.as_ref());

        let parsed = parser.parse();
        let values = match parsed {
            Some(v) => v,
            None => {
                // We can unwrap here, becase parser.parse() == None means there were errors
                let err : Box<Error> = parser.errors.pop().unwrap().into();
                return Err(err)
            }
        };
        let table : toml::Value = toml::Value::Table(values);
        let mut decoder = toml::Decoder::new(table);
        let p = try!(rustc_serialize::Decodable::decode(&mut decoder));
        Ok(p)
    }
}

impl Default for Palette {
    fn default() -> Self {
        Palette {
            default_colors : FromIterator::from_iter(DEFAULT_COLORS.iter().map(
                |&(r,g,b)|{Color(r,g,b)}
            )),
            partials : PartialIDer::new(8, true),
            assigned : HashMap::new(),
            next_color : 0
        }
    }
}

#[derive(Serialize, RustcEncodable, Copy, Clone)]
struct AssignmentRef<'a> {
    names : &'a ObjectID,
    color : &'a Color
}

fn to_assignments<'a>(assigned : &'a HashMap<ObjectID, Color>) -> Vec<AssignmentRef<'a>> {
    assigned.into_iter().map(|(k, v)| {
        AssignmentRef{
            names : k,
            color : v
        }
    }).collect()
}

/// A reference to a palette, with minimal data, for serialization purposes
#[derive(Serialize, RustcEncodable, Clone)]
pub struct PaletteRef<'a> {
    defaults : &'a Vec<Color>,
    partials : &'a PartialIDer,
    assigned : Vec<AssignmentRef<'a>>
}

impl<'a> From<&'a Palette> for PaletteRef<'a> {
    fn from(palette: &'a Palette) -> Self {
        PaletteRef {
            defaults : &palette.default_colors,
            partials : &palette.partials,
            assigned : to_assignments(&palette.assigned),
        }
    }
}

#[derive(Deserialize, RustcDecodable, Clone)]
struct Assignment {
    names : ObjectID,
    color : Color
}

fn from_assignments(assigned : Vec<Assignment>) -> HashMap<ObjectID, Color> {
    assigned.into_iter().map(|a| {
        (a.names, a.color)
    }).collect()
}

/// A reference to a palette, with minimal data
#[derive(Deserialize, RustcDecodable, Clone)]
pub struct PaletteBasic {
    defaults : Vec<Color>,
    partials : PartialIDer,
    assigned : Option<Vec<Assignment>>,
    next_color : Option<usize>
}

impl From<PaletteBasic> for Palette {
    fn from(p : PaletteBasic) -> Self {
        Palette {
            default_colors : p.defaults,
            partials : p.partials,
            assigned : p.assigned.map(from_assignments).unwrap_or_default(),
            next_color : p.next_color.unwrap_or(0)
        }
    }
}

//TODO: add test for round-trip through toml and json

impl serde::Serialize for Color {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer {
        let &Color(r,g,b) = self;
        serde::Serialize::serialize(&(r,g,b), serializer)
    }
}

impl serde::Deserialize for Color {
    fn deserialize<D : serde::Deserializer>(deserializer: &mut D) -> Result<Self, D::Error> {
        let (r,g,b) = try!(serde::Deserialize::deserialize(deserializer));
        Ok(Color(r,g,b))
    }
}

impl rustc_serialize::Encodable for Color {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let &Color(r,g,b) = self;
        rustc_serialize::Encodable::encode(&(r,g,b), s)
    }
}

impl rustc_serialize::Decodable for Color {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let (r,g,b) = try!(rustc_serialize::Decodable::decode(d));
        Ok(Color(r,g,b))
    }
}

impl serde::Serialize for Palette {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer {
        PaletteRef::from(self).serialize(serializer)
    }
}

impl serde::Deserialize for Palette {
    fn deserialize<D : serde::Deserializer>(deserializer: &mut D) -> Result<Self, D::Error>  {
        let p = try!(PaletteBasic::deserialize(deserializer));
        Ok(Palette::from(p))
    }
}

impl rustc_serialize::Encodable for Palette {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        PaletteRef::from(self).encode(s)
    }
}

impl rustc_serialize::Decodable for Palette {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let p = try!(PaletteBasic::decode(d));
        Ok(Palette::from(p))
    }
}
<|endoftext|>


<commit_before>//! A palette for use with Objects

use na;
use serde;

#[cfg(test)]
use serde_json;
#[cfg(test)]
use toml;

use std::collections::HashMap;
use std::iter::{repeat, FromIterator};

use kiss3d::scene::SceneNode;
use serde::{Deserialize, Serialize};

use objects::ObjectID;

/// An RGB color
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone, Debug)]
pub struct Color(pub u8, pub u8, pub u8);

/// Default colors to use, when no others are specified.
pub static DEFAULT_COLORS: [(u8, u8, u8); 11] = [
    (77, 175, 74),   // Green
    (152, 78, 163),  // Purple
    (255, 127, 0),   // Orange
    (228, 26, 28),   // Red
    (55, 126, 184),  // Blue
    (166, 86, 40),   // Brown
    (247, 129, 191), // Pink
    (153, 153, 153), // Gray
    (255, 255, 51),  // Yellow
    (255, 255, 255), // White
    (0, 0, 0),       // Black
];

impl Color {
    /// Convert to a 3-tuple, from 0 to 1
    pub fn to_floats(self) -> (f32, f32, f32) {
        let Color(r, g, b) = self;
        (
            (r as f32) / (u8::max_value() as f32),
            (g as f32) / (u8::max_value() as f32),
            (b as f32) / (u8::max_value() as f32),
        )
    }

    /// Convert to `na::Point3`, needed for `kiss3d::window::Window::draw_text`
    pub fn to_point3(self) -> na::Point3<f32> {
        let (r, g, b) = self.to_floats();

        na::Point3::new(r, g, b)
    }
}

/// A [bool] for keeping track of which part of the objectID should be used
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
pub struct PartialIDer {
    /// Which sections of an ObjectID should be converted
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub bools: Vec<bool>,
}

impl PartialIDer {
    /// New, with all set to given boolean value
    pub fn new(n: usize, value: bool) -> Self {
        PartialIDer {
            bools: repeat(value).take(n).collect(),
        }
    }

    /// is_empty returns true if there are no partial ids
    pub fn is_empty(&self) -> bool {
        self.bools.is_empty()
    }

    /// Get the portion of an ID
    pub fn partial<'a>(&self, name: &'a ObjectID) -> Vec<&'a str> {
        let &ObjectID(ref names) = name;
        names
            .iter()
            .zip(self.bools.iter())
            .filter_map(|(n, &b)| if b { Some(&n[..]) } else { None })
            .collect()
    }

    /// Get the portion of an ID
    pub fn as_id(&self, name: &ObjectID) -> ObjectID {
        let &ObjectID(ref names) = name;
        ObjectID(
            names
                .iter()
                .zip(self.bools.iter())
                .filter_map(|(n, &b)| if b { Some(n.clone()) } else { None })
                .collect(),
        )
    }

    /// Get a string representing the current state
    pub fn as_string(&self) -> String {
        let mut s = String::with_capacity(self.bools.len());
        let pieces: Vec<String> = self
            .bools
            .iter()
            .enumerate()
            .map(|(n, &b)| {
                if b {
                    format!("{}", (n + 1) % 10)
                } else {
                    String::from("_")
                }
            })
            .collect();
        s.extend(pieces.iter().map(|p| &p[0..1]));
        s
    }
}

/// A way to convert string names to colors
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Palette {
    default_colors: Vec<Color>,
    partials: PartialIDer,

    /// Mapping of names -> colors, when found. names not found will be given default colors.
    pub assigned: HashMap<ObjectID, Color>,
    next_color: usize,
}

impl Palette {
    /// Set the color of an object to match what the palette says
    pub fn set_color(&mut self, name: &ObjectID, node: &mut SceneNode) {
        let (r, g, b) = self.get_color(name).to_floats();
        node.set_color(r, g, b);
    }

    /// Get the color for a particular ID (using partials mask)
    pub fn get_color(&mut self, name: &ObjectID) -> Color {
        let partial = self.partials.as_id(name);
        let (next_color, default_colors, assigned) = (
            &mut self.next_color,
            &self.default_colors,
            &mut self.assigned,
        );

        *assigned.entry(partial).or_insert_with(|| {
            let col = default_colors[*next_color];
            *next_color = (*next_color + 1) % default_colors.len();
            col
        })
    }

    /// Toggle whether or not to use a certain partial value
    pub fn toggle_partial(&mut self, n: usize) {
        if n > self.partials.bools.len() {
            return;
        };
        self.partials.bools[n] = !self.partials.bools[n];
        self.next_color = 0;
    }

    /// Check value of a certain partial
    pub fn get_partial(&mut self, n: usize) -> bool {
        self.partials.bools[n]
    }

    /// Check value of a certain partial
    pub fn set_partial(&mut self, n: usize, value: bool) {
        self.partials.bools[n] = value;
        self.next_color = 0;
    }

    /// Check value of a certain partial
    pub fn set_all_partial(&mut self, value: bool) {
        let n = self.partials.bools.len();
        for i in 0..n {
            self.partials.bools[i] = value;
        }
        self.next_color = 0;
    }

    /// Get a string like '_23____' for which parts of the ObjectID we are coloring with respect to
    pub fn partials_string(&self) -> String {
        self.partials.as_string()
    }
}

impl Default for Palette {
    fn default() -> Self {
        Palette {
            default_colors: FromIterator::from_iter(
                DEFAULT_COLORS.iter().map(|&(r, g, b)| Color(r, g, b)),
            ),
            partials: PartialIDer::new(8, true),
            assigned: HashMap::new(),
            next_color: 0,
        }
    }
}

#[derive(Serialize, Debug, Copy, Clone)]
struct AssignmentRef<'a> {
    #[serde(skip_serializing_if = "ObjectID::is_empty")]
    names: &'a ObjectID,
    color: &'a Color,
}

fn to_assignments(assigned: &HashMap<ObjectID, Color>) -> Vec<AssignmentRef> {
    assigned
        .into_iter()
        .map(|(k, v)| AssignmentRef { names: k, color: v })
        .collect()
}

/// A reference to a palette, with minimal data, for serialization purposes
#[derive(Serialize, Debug, Clone)]
pub struct PaletteRef<'a> {
    #[serde(skip_serializing_if = "PartialIDer::is_empty")]
    partials: &'a PartialIDer,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    assigned: Vec<AssignmentRef<'a>>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    default_colors: &'a Vec<Color>,
}

impl<'a> From<&'a Palette> for PaletteRef<'a> {
    fn from(palette: &'a Palette) -> Self {
        PaletteRef {
            default_colors: &palette.default_colors,
            partials: &palette.partials,
            assigned: to_assignments(&palette.assigned),
        }
    }
}

#[derive(Deserialize, Clone)]
struct Assignment {
    names: ObjectID,
    color: Color,
}

fn from_assignments(assigned: Vec<Assignment>) -> HashMap<ObjectID, Color> {
    assigned.into_iter().map(|a| (a.names, a.color)).collect()
}

/// A palette with all fields optional, for deserializing a config.
#[derive(Deserialize, Clone)]
struct PaletteOpt {
    default_colors: Option<Vec<Color>>,
    partials: Option<PartialIDer>,
    assigned: Option<Vec<Assignment>>,
    next_color: Option<usize>,
}

impl PaletteOpt {
    fn into_palette(self) -> Palette {
        let default_palette = Palette::default();

        Palette {
            default_colors: self
                .default_colors
                .unwrap_or(default_palette.default_colors),
            partials: self.partials.unwrap_or(default_palette.partials),
            assigned: self
                .assigned
                .map(from_assignments)
                .unwrap_or(default_palette.assigned),
            next_color: self.next_color.unwrap_or(default_palette.next_color),
        }
    }
}

impl Serialize for Color {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let &Color(r, g, b) = self;
        Serialize::serialize(&(r, g, b), serializer)
    }
}

impl<'de> Deserialize<'de> for Color {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let (r, g, b) = Deserialize::deserialize(deserializer)?;
        Ok(Color(r, g, b))
    }
}

impl Serialize for Palette {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        PaletteRef::from(self).serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for Palette {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let p = try!(PaletteOpt::deserialize(deserializer));
        Ok(p.into_palette())
    }
}

#[test]
fn palette_toml_round_trip() -> Result<(), Box<std::error::Error>> {
    let mut p = Palette::default();
    let _ = p
        .assigned
        .insert(ObjectID(vec!["abc".into()]), Color(1, 2, 3));

    println!("default: {:#?}", p);
    let mut pr = PaletteRef::from(&p);
    println!("pr: {:#?}", pr);

    let ra = toml::to_string(&pr.assigned);
    println!("ra returned: {:#?}", ra);
    let dc = toml::to_string(&pr.default_colors);
    println!("dc returned: {:#?}", dc);
    let partials = toml::to_string(&pr.partials);
    println!("partials returned: {:#?}", partials);

    let rpr = toml::to_string(&pr);
    println!("rpr returned: {:#?}", rpr);

    let r = toml::to_string(&p);
    println!("returned: {:#?}", r);
    let s = r?;
    println!("to_string: {}", s);
    let p2 = toml::from_str(&*s)?;
    println!("from_str: {:#?}", p2);
    assert_eq!(p, p2);
    Ok(())
}

#[test]
fn palette_toml_empty_string() {
    let p = Palette::default();
    let p2 = toml::from_str("").unwrap();
    assert_eq!(p, p2);
}

#[test]
fn palette_json_round_trip() {
    let p = Palette::default();

    let s = serde_json::to_string_pretty(&p).unwrap();
    let p2 = serde_json::from_str(&*s).unwrap();
    assert_eq!(p, p2);
}
<commit_msg>Tests pass<commit_after>//! A palette for use with Objects

use na;
use serde;

#[cfg(test)]
use serde_json;
#[cfg(test)]
use toml;

use std::collections::HashMap;
use std::iter::{repeat, FromIterator};

use kiss3d::scene::SceneNode;
use serde::{Deserialize, Serialize};

use objects::ObjectID;

/// An RGB color
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone, Debug)]
pub struct Color(pub u8, pub u8, pub u8);

/// Default colors to use, when no others are specified.
pub static DEFAULT_COLORS: [(u8, u8, u8); 11] = [
    (77, 175, 74),   // Green
    (152, 78, 163),  // Purple
    (255, 127, 0),   // Orange
    (228, 26, 28),   // Red
    (55, 126, 184),  // Blue
    (166, 86, 40),   // Brown
    (247, 129, 191), // Pink
    (153, 153, 153), // Gray
    (255, 255, 51),  // Yellow
    (255, 255, 255), // White
    (0, 0, 0),       // Black
];

impl Color {
    /// Convert to a 3-tuple, from 0 to 1
    pub fn to_floats(self) -> (f32, f32, f32) {
        let Color(r, g, b) = self;
        (
            (r as f32) / (u8::max_value() as f32),
            (g as f32) / (u8::max_value() as f32),
            (b as f32) / (u8::max_value() as f32),
        )
    }

    /// Convert to `na::Point3`, needed for `kiss3d::window::Window::draw_text`
    pub fn to_point3(self) -> na::Point3<f32> {
        let (r, g, b) = self.to_floats();

        na::Point3::new(r, g, b)
    }
}

/// A [bool] for keeping track of which part of the objectID should be used
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
pub struct PartialIDer {
    /// Which sections of an ObjectID should be converted
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub bools: Vec<bool>,
}

impl PartialIDer {
    /// New, with all set to given boolean value
    pub fn new(n: usize, value: bool) -> Self {
        PartialIDer {
            bools: repeat(value).take(n).collect(),
        }
    }

    /// is_empty returns true if there are no partial ids
    pub fn is_empty(&self) -> bool {
        self.bools.is_empty()
    }

    /// Get the portion of an ID
    pub fn partial<'a>(&self, name: &'a ObjectID) -> Vec<&'a str> {
        let &ObjectID(ref names) = name;
        names
            .iter()
            .zip(self.bools.iter())
            .filter_map(|(n, &b)| if b { Some(&n[..]) } else { None })
            .collect()
    }

    /// Get the portion of an ID
    pub fn as_id(&self, name: &ObjectID) -> ObjectID {
        let &ObjectID(ref names) = name;
        ObjectID(
            names
                .iter()
                .zip(self.bools.iter())
                .filter_map(|(n, &b)| if b { Some(n.clone()) } else { None })
                .collect(),
        )
    }

    /// Get a string representing the current state
    pub fn as_string(&self) -> String {
        let mut s = String::with_capacity(self.bools.len());
        let pieces: Vec<String> = self
            .bools
            .iter()
            .enumerate()
            .map(|(n, &b)| {
                if b {
                    format!("{}", (n + 1) % 10)
                } else {
                    String::from("_")
                }
            })
            .collect();
        s.extend(pieces.iter().map(|p| &p[0..1]));
        s
    }
}

/// A way to convert string names to colors
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Palette {
    default_colors: Vec<Color>,
    partials: PartialIDer,

    /// Mapping of names -> colors, when found. names not found will be given default colors.
    pub assigned: HashMap<ObjectID, Color>,
    next_color: usize,
}

impl Palette {
    /// Set the color of an object to match what the palette says
    pub fn set_color(&mut self, name: &ObjectID, node: &mut SceneNode) {
        let (r, g, b) = self.get_color(name).to_floats();
        node.set_color(r, g, b);
    }

    /// Get the color for a particular ID (using partials mask)
    pub fn get_color(&mut self, name: &ObjectID) -> Color {
        let partial = self.partials.as_id(name);
        let (next_color, default_colors, assigned) = (
            &mut self.next_color,
            &self.default_colors,
            &mut self.assigned,
        );

        *assigned.entry(partial).or_insert_with(|| {
            let col = default_colors[*next_color];
            *next_color = (*next_color + 1) % default_colors.len();
            col
        })
    }

    /// Toggle whether or not to use a certain partial value
    pub fn toggle_partial(&mut self, n: usize) {
        if n > self.partials.bools.len() {
            return;
        };
        self.partials.bools[n] = !self.partials.bools[n];
        self.next_color = 0;
    }

    /// Check value of a certain partial
    pub fn get_partial(&mut self, n: usize) -> bool {
        self.partials.bools[n]
    }

    /// Check value of a certain partial
    pub fn set_partial(&mut self, n: usize, value: bool) {
        self.partials.bools[n] = value;
        self.next_color = 0;
    }

    /// Check value of a certain partial
    pub fn set_all_partial(&mut self, value: bool) {
        let n = self.partials.bools.len();
        for i in 0..n {
            self.partials.bools[i] = value;
        }
        self.next_color = 0;
    }

    /// Get a string like '_23____' for which parts of the ObjectID we are coloring with respect to
    pub fn partials_string(&self) -> String {
        self.partials.as_string()
    }
}

impl Default for Palette {
    fn default() -> Self {
        Palette {
            default_colors: FromIterator::from_iter(
                DEFAULT_COLORS.iter().map(|&(r, g, b)| Color(r, g, b)),
            ),
            partials: PartialIDer::new(8, true),
            assigned: HashMap::new(),
            next_color: 0,
        }
    }
}

#[derive(Serialize, Debug, Copy, Clone)]
struct AssignmentRef<'a> {
    #[serde(skip_serializing_if = "ObjectID::is_empty")]
    names: &'a ObjectID,
    color: &'a Color,
}

fn to_assignments(assigned: &HashMap<ObjectID, Color>) -> Vec<AssignmentRef> {
    assigned
        .into_iter()
        .map(|(k, v)| AssignmentRef { names: k, color: v })
        .collect()
}

/// A reference to a palette, with minimal data, for serialization purposes
#[derive(Serialize, Debug, Clone)]
pub struct PaletteRef<'a> {
    #[serde(skip_serializing_if = "Vec::is_empty")]
    defaults: &'a Vec<Color>,
    #[serde(skip_serializing_if = "PartialIDer::is_empty")]
    partials: &'a PartialIDer,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    assigned: Vec<AssignmentRef<'a>>,
}

impl<'a> From<&'a Palette> for PaletteRef<'a> {
    fn from(palette: &'a Palette) -> Self {
        PaletteRef {
            defaults: &palette.default_colors,
            partials: &palette.partials,
            assigned: to_assignments(&palette.assigned),
        }
    }
}

#[derive(Deserialize, Clone)]
struct Assignment {
    names: ObjectID,
    color: Color,
}

fn from_assignments(assigned: Vec<Assignment>) -> HashMap<ObjectID, Color> {
    assigned.into_iter().map(|a| (a.names, a.color)).collect()
}

/// A palette with all fields optional, for deserializing a config.
#[derive(Deserialize, Clone)]
struct PaletteOpt {
    default_colors: Option<Vec<Color>>,
    partials: Option<PartialIDer>,
    assigned: Option<Vec<Assignment>>,
    next_color: Option<usize>,
}

impl PaletteOpt {
    fn into_palette(self) -> Palette {
        let default_palette = Palette::default();

        Palette {
            default_colors: self
                .default_colors
                .unwrap_or(default_palette.default_colors),
            partials: self.partials.unwrap_or(default_palette.partials),
            assigned: self
                .assigned
                .map(from_assignments)
                .unwrap_or(default_palette.assigned),
            next_color: self.next_color.unwrap_or(default_palette.next_color),
        }
    }
}

impl Serialize for Color {
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let &Color(r, g, b) = self;
        Serialize::serialize(&(r, g, b), serializer)
    }
}

impl<'de> Deserialize<'de> for Color {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let (r, g, b) = Deserialize::deserialize(deserializer)?;
        Ok(Color(r, g, b))
    }
}

impl Serialize for Palette {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        PaletteRef::from(self).serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for Palette {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let p = try!(PaletteOpt::deserialize(deserializer));
        Ok(p.into_palette())
    }
}

#[test]
fn palette_toml_round_trip() -> Result<(), Box<std::error::Error>> {
    let p = Palette::default();
    let s = toml::to_string(&p)?;
    let p2 = toml::from_str(&*s)?;
    assert_eq!(p, p2);
    Ok(())
}

#[test]
fn palette_toml_empty_string() {
    let p = Palette::default();
    let p2 = toml::from_str("").unwrap();
    assert_eq!(p, p2);
}

#[test]
fn palette_json_round_trip() {
    let p = Palette::default();

    let s = serde_json::to_string_pretty(&p).unwrap();
    let p2 = serde_json::from_str(&*s).unwrap();
    assert_eq!(p, p2);
}
<|endoftext|>


<commit_before>use State;
use project;

use std::cell::RefCell;
use std::fs::File;
use std::io::prelude::*;

extern crate git2;
use self::git2::Repository;
use self::git2::Reference;
use self::git2::StatusOptions;
use self::git2::Delta;
use self::git2::BranchType;
use self::git2::{Diff, DiffFormat, DiffDelta, DiffHunk, DiffLine, DiffBinary};
use git2::ObjectType;

extern crate md5;
extern crate chrono;
use maud::PreEscaped;
use self::chrono::{TimeZone, FixedOffset};

use yaml_rust::{Yaml, YamlLoader};

extern crate base64;

use self::base64::{encode, decode};

pub fn generate(previous_commit: Option<State>) -> String {
    let current = project::current();
    let repo = Repository::discover(".").unwrap();
    let mut revwalk = repo.revwalk().unwrap();
    revwalk.set_sorting(git2::SORT_REVERSE);
    revwalk.push_head().unwrap();

    let head = repo.head().unwrap().peel(ObjectType::Tree).unwrap();
    let head_tree = head.as_tree().unwrap();
    let changes = repo.diff_tree_to_index(Some(&head_tree), None, None).unwrap();

    let mut status_opts = StatusOptions::new();
    status_opts.include_untracked(true);

    let payload = html! {
        state {
            @if let Some(commit) = previous_commit.clone() {
                focus (commit.focus)
            }
            user {
                name  (current.user.name)
                email (current.user.email)
            }
            task {
                name (current.task.id)
            }
            @if let Ok(branches) = repo.branches(None) {
                tasks {
                    @for (branch, branch_type) in branches.map(|b|b.unwrap()).filter(|&(ref b, t)| !b.is_head()) {
                        task {
                            name (branch.name().ok().unwrap().unwrap())
                            type @match branch_type {
                                BranchType::Remote => "remote",
                                BranchType::Local => "local",
                                _ => ""
                            }
                        }
                    }
                }
            }
            log {
                @for rev in revwalk {
                    @let commit = repo.find_commit(rev.unwrap()).unwrap() {
                        commit {
                            id (commit.id())
                            @let time = commit.time() {
                                timestamp (time.seconds())
                                localtime (FixedOffset::east(time.offset_minutes()*60).timestamp(time.seconds(), 0).to_rfc3339())
                            }
                            user {
                                @let author = commit.author() {
                                    name (author.name().unwrap())
                                    @let email = author.email().unwrap().trim() {
                                        email (email)
                                        image (format!("https://www.gravatar.com/avatar/{:x}?s=64", md5::compute(email.to_lowercase())))
                                    }
                                }
                            }
                            @let mut message = commit.message().unwrap().split("---\n") {
                                message (message.next().unwrap())
                                @if let Some(yaml) = message.next() {
                                    @for (task, values) in YamlLoader::load_from_str(yaml).unwrap()[0].as_hash().unwrap() {
                                        task {
                                            name (task.as_str().unwrap_or("None"))
                                            @for (name, value) in values.as_hash().unwrap() {
                                                property {
                                                    name (name.as_str().unwrap_or("[]"))
                                                    @for parent in commit.parents() {
                                                        @let mut propwalk = repo.revwalk().unwrap() {
                                                            @if let Ok(_) = propwalk.push(parent.id()) {
                                                                @for proprev in propwalk {
                                                                    @let propcommit = repo.find_commit(proprev.unwrap()).unwrap() {
                                                                        @let mut propmessages = propcommit.message().unwrap().split("---\n") {
                                                                            @if let Some(propmessage) = propmessages.next() {
                                                                                @if let Some(yaml) = propmessages.next() {
                                                                                @for (proptask, propvalues) in YamlLoader::load_from_str(yaml).unwrap()[0].as_hash().unwrap() {
                                                                                @if proptask == proptask {
                                                                                @for (propname, propvalue) in propvalues.as_hash().unwrap() {
                                                                                @if propname == name {
                                                                                @if let Some(propbefore) = propvalue.as_str() {
                                                                                before (propbefore)
                                                                                }
                                                                                }
                                                                                }
                                                                                }
                                                                                }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                    after {
                                                        @match value {
                                                            &Yaml::Integer(int) => (int),
                                                            &Yaml::String(ref string) => (string),
                                                            &Yaml::Boolean(b) => (b),
                                                            _ => ("[unknown]")
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(commit) = previous_commit.clone() {
                properties {
                    @for property in commit.property {
                        property {
                            name (property.name)
                            value (property.value)
                            options {
                                option "Sprint"
                                option "In Progress"
                                option "In Review"
                                option "Blocked"
                                option "Done"
                            }
                        }
                    }
                }
                message (commit.message)
            } @else {
                properties {
                    property {
                        name "Status"
                        value "Done"
                        options {
                            option "Sprint"
                            option "In Progress"
                            option "In Review"
                            option "Blocked"
                            option "Done"
                        }
                    }
                    property {
                        name "Estimate"
                        value "5"
                    }
                    property {
                        name "Developer"
                        value "Jaden Carver <jaden.carver@gmail.com>"
                        options {
                            option value="Jaden Carver <jaden.carver@gmail.com>" "Jaden Carver"
                            option value="Bob Dole <bdole69@gmail.com>" "Bob Dole"
                        }
                    }
                    property {
                        name "Description"
                        value ""
                    }
                }
            }
            changes {
                @if let Ok(delta) = changes.stats() {
                    statistics {
                        files (delta.files_changed())
                        insertions (delta.insertions())
                        deletions (delta.deletions())
                    }
                }
                @for change in repo.statuses(Some(&mut status_opts)).unwrap().iter() {
                    @let path = change.path().unwrap() {
                        change id=(path.replace("/", "_").replace(".", "_").replace(" ", "_")) {
                            path (path)
                            insertions {}
                            deletions {}
                            included @match change.head_to_index().map(|d| d.status()).unwrap_or(Delta::Unreadable) {
                                Delta::Modified | Delta::Added | Delta::Deleted => "true",
                                _ => "false"
                            }
                            removal @match change.head_to_index().map(|d| d.status()).unwrap_or(Delta::Unreadable) {
                                Delta::Deleted => "true",
                                _ => "false"
                            }
                        }
                    }
                }
            }
            diffs {
                @for change in diff(changes) {
                    (change)
                }
            }
        }
    }.into_string();
    payload
}

fn diff(changes: Diff) -> Vec<PreEscaped<String>> {
    let mut result = RefCell::new(vec![]);
    changes.foreach(&mut |delta: DiffDelta, i: f32| {
        result.borrow_mut().push(html!(
            @if let Some(path) = delta.new_file().path() {
                label (path.to_str().unwrap_or("[invalid]"))
            }
        ));
        true
    }, Some(&mut |delta: DiffDelta, binary: DiffBinary| {
        if binary.contains_data() {
            result.borrow_mut().push(html!(
                img src=(format!("data:image/jpeg,{}", (String::from_utf8_lossy(&binary.new_file().data())))) {}
            ));
        } else {
            let path = delta.new_file().path().unwrap();
            println!("{:?}", path);
            let mut file = File::open(path).unwrap();
            println!("{:?}", file);
            let mut contents = vec![];
            file.read_to_end(&mut contents).unwrap();
            println!("{:?}", contents);
            result.borrow_mut().push(html!(
                img src=(format!("data:image/jpeg;base64,{}", encode(&contents))) alt=(format!("{}", path.to_str().unwrap())) {}
            ));
        }
        true
    }), None, Some(&mut |delta: DiffDelta, hunk: Option<DiffHunk>, line: DiffLine| {
        let class = match line.origin() {
            '+' | '>' => "add",
            '-' | '<' => "sub",
            'H' | 'F' => "meta",
            _ => ""
        };
        result.borrow_mut().push(html!(
            span class=(class) (String::from_utf8_lossy(&line.content()))
        ));
        true
    }));
    result.into_inner()
}
<commit_msg>Removes debug lines --- "BLBA-1234":    Description: ""   Developer: Sprint   Estimate: "5"   Status: Sprint<commit_after>use State;
use project;

use std::cell::RefCell;
use std::fs::File;
use std::io::prelude::*;

extern crate git2;
use self::git2::Repository;
use self::git2::Reference;
use self::git2::StatusOptions;
use self::git2::Delta;
use self::git2::BranchType;
use self::git2::{Diff, DiffFormat, DiffDelta, DiffHunk, DiffLine, DiffBinary};
use git2::ObjectType;

extern crate md5;
extern crate chrono;
use maud::PreEscaped;
use self::chrono::{TimeZone, FixedOffset};

use yaml_rust::{Yaml, YamlLoader};

extern crate base64;

use self::base64::{encode, decode};

pub fn generate(previous_commit: Option<State>) -> String {
    let current = project::current();
    let repo = Repository::discover(".").unwrap();
    let mut revwalk = repo.revwalk().unwrap();
    revwalk.set_sorting(git2::SORT_REVERSE);
    revwalk.push_head().unwrap();

    let head = repo.head().unwrap().peel(ObjectType::Tree).unwrap();
    let head_tree = head.as_tree().unwrap();
    let changes = repo.diff_tree_to_index(Some(&head_tree), None, None).unwrap();

    let mut status_opts = StatusOptions::new();
    status_opts.include_untracked(true);

    let payload = html! {
        state {
            @if let Some(commit) = previous_commit.clone() {
                focus (commit.focus)
            }
            user {
                name  (current.user.name)
                email (current.user.email)
            }
            task {
                name (current.task.id)
            }
            @if let Ok(branches) = repo.branches(None) {
                tasks {
                    @for (branch, branch_type) in branches.map(|b|b.unwrap()).filter(|&(ref b, t)| !b.is_head()) {
                        task {
                            name (branch.name().ok().unwrap().unwrap())
                            type @match branch_type {
                                BranchType::Remote => "remote",
                                BranchType::Local => "local",
                                _ => ""
                            }
                        }
                    }
                }
            }
            log {
                @for rev in revwalk {
                    @let commit = repo.find_commit(rev.unwrap()).unwrap() {
                        commit {
                            id (commit.id())
                            @let time = commit.time() {
                                timestamp (time.seconds())
                                localtime (FixedOffset::east(time.offset_minutes()*60).timestamp(time.seconds(), 0).to_rfc3339())
                            }
                            user {
                                @let author = commit.author() {
                                    name (author.name().unwrap())
                                    @let email = author.email().unwrap().trim() {
                                        email (email)
                                        image (format!("https://www.gravatar.com/avatar/{:x}?s=64", md5::compute(email.to_lowercase())))
                                    }
                                }
                            }
                            @let mut message = commit.message().unwrap().split("---\n") {
                                message (message.next().unwrap())
                                @if let Some(yaml) = message.next() {
                                    @for (task, values) in YamlLoader::load_from_str(yaml).unwrap()[0].as_hash().unwrap() {
                                        task {
                                            name (task.as_str().unwrap_or("None"))
                                            @for (name, value) in values.as_hash().unwrap() {
                                                property {
                                                    name (name.as_str().unwrap_or("[]"))
                                                    @for parent in commit.parents() {
                                                        @let mut propwalk = repo.revwalk().unwrap() {
                                                            @if let Ok(_) = propwalk.push(parent.id()) {
                                                                @for proprev in propwalk {
                                                                    @let propcommit = repo.find_commit(proprev.unwrap()).unwrap() {
                                                                        @let mut propmessages = propcommit.message().unwrap().split("---\n") {
                                                                            @if let Some(propmessage) = propmessages.next() {
                                                                                @if let Some(yaml) = propmessages.next() {
                                                                                @for (proptask, propvalues) in YamlLoader::load_from_str(yaml).unwrap()[0].as_hash().unwrap() {
                                                                                @if proptask == proptask {
                                                                                @for (propname, propvalue) in propvalues.as_hash().unwrap() {
                                                                                @if propname == name {
                                                                                @if let Some(propbefore) = propvalue.as_str() {
                                                                                before (propbefore)
                                                                                }
                                                                                }
                                                                                }
                                                                                }
                                                                                }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                    after {
                                                        @match value {
                                                            &Yaml::Integer(int) => (int),
                                                            &Yaml::String(ref string) => (string),
                                                            &Yaml::Boolean(b) => (b),
                                                            _ => ("[unknown]")
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(commit) = previous_commit.clone() {
                properties {
                    @for property in commit.property {
                        property {
                            name (property.name)
                            value (property.value)
                            options {
                                option "Sprint"
                                option "In Progress"
                                option "In Review"
                                option "Blocked"
                                option "Done"
                            }
                        }
                    }
                }
                message (commit.message)
            } @else {
                properties {
                    property {
                        name "Status"
                        value "Done"
                        options {
                            option "Sprint"
                            option "In Progress"
                            option "In Review"
                            option "Blocked"
                            option "Done"
                        }
                    }
                    property {
                        name "Estimate"
                        value "5"
                    }
                    property {
                        name "Developer"
                        value "Jaden Carver <jaden.carver@gmail.com>"
                        options {
                            option value="Jaden Carver <jaden.carver@gmail.com>" "Jaden Carver"
                            option value="Bob Dole <bdole69@gmail.com>" "Bob Dole"
                        }
                    }
                    property {
                        name "Description"
                        value ""
                    }
                }
            }
            changes {
                @if let Ok(delta) = changes.stats() {
                    statistics {
                        files (delta.files_changed())
                        insertions (delta.insertions())
                        deletions (delta.deletions())
                    }
                }
                @for change in repo.statuses(Some(&mut status_opts)).unwrap().iter() {
                    @let path = change.path().unwrap() {
                        change id=(path.replace("/", "_").replace(".", "_").replace(" ", "_")) {
                            path (path)
                            insertions {}
                            deletions {}
                            included @match change.head_to_index().map(|d| d.status()).unwrap_or(Delta::Unreadable) {
                                Delta::Modified | Delta::Added | Delta::Deleted => "true",
                                _ => "false"
                            }
                            removal @match change.head_to_index().map(|d| d.status()).unwrap_or(Delta::Unreadable) {
                                Delta::Deleted => "true",
                                _ => "false"
                            }
                        }
                    }
                }
            }
            diffs {
                @for change in diff(changes) {
                    (change)
                }
            }
        }
    }.into_string();
    payload
}

fn diff(changes: Diff) -> Vec<PreEscaped<String>> {
    let mut result = RefCell::new(vec![]);
    changes.foreach(&mut |delta: DiffDelta, i: f32| {
        result.borrow_mut().push(html!(
            @if let Some(path) = delta.new_file().path() {
                label (path.to_str().unwrap_or("[invalid]"))
            }
        ));
        true
    }, Some(&mut |delta: DiffDelta, binary: DiffBinary| {
        if binary.contains_data() {
            result.borrow_mut().push(html!(
                img src=(format!("data:image/jpeg,{}", (String::from_utf8_lossy(&binary.new_file().data())))) {}
            ));
        } else {
            let path = delta.new_file().path().unwrap();
            let mut file = File::open(path).unwrap();
            let mut contents = vec![];
            file.read_to_end(&mut contents).unwrap();
            result.borrow_mut().push(html!(
                img src=(format!("data:image/jpeg;base64,{}", encode(&contents))) alt=(format!("{}", path.to_str().unwrap())) {}
            ));
        }
        true
    }), None, Some(&mut |delta: DiffDelta, hunk: Option<DiffHunk>, line: DiffLine| {
        let class = match line.origin() {
            '+' | '>' => "add",
            '-' | '<' => "sub",
            'H' | 'F' => "meta",
            _ => ""
        };
        result.borrow_mut().push(html!(
            span class=(class) (String::from_utf8_lossy(&line.content()))
        ));
        true
    }));
    result.into_inner()
}
<|endoftext|>


<commit_before>use libc;

extern {
    #[cfg(test)]
    fn highbd_dc_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_dc_left_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_dc_top_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    #[cfg(test)]
    fn highbd_h_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);

    #[cfg(test)]
    fn highbd_v_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
        bh: libc::c_int, above: *const u16,
        left: *const u16, bd: libc::c_int);
}

pub fn pred_dc_128(output: &mut [u16], stride: usize) {
    for y in 0..4 {
        for x in 0..4 {
            output[y*stride+x] = 128;
        }
    }
}

pub fn pred_dc_left_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_left_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc_top_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_top_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    let edges = left.iter().chain(above.iter());
    let len = (left.len() + above.len()) as u32;
    let bw = above.len();
    let bh = left.len();
    let avg = (edges.fold(0, |acc, &v| acc + v as u32) + (len >> 1)) / len;

    for line in output.chunks_mut(stride).take(bh) {
        for v in &mut line[..bw] {
            *v = avg as u16;
        }
    }
}

pub fn pred_h(output: &mut [u16], stride: usize, left: &[u16], bw: usize) {
  for (line, l) in output.chunks_mut(stride).zip(left) {
    for v in &mut line[..bw] {
      *v = *l;
    }
  }
}

pub fn pred_v(output: &mut [u16], stride: usize, above: &[u16], bh: usize) {
    let bw = above.len();
    for line in output.chunks_mut(stride).take(bh) {
        line[..bw].clone_from_slice(above)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rand::{ChaChaRng, Rng};
    use test::Bencher;

    const MAX_ITER: usize = 1000;

    fn setup_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>, Vec<u16>, Vec<u16>) {
        let output = vec![0u16; 32 * 32];
        let above: Vec<u16> = (0..32).map(|_| ra.gen()).collect();
        let left: Vec<u16> = (0..32).map(|_| ra.gen()).collect();

        let o1 = output.clone();
        let o2 = output.clone();

        (above, left, o1, o2)
    }

    fn pred_dc_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
        unsafe {
            highbd_dc_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
        }
    }

    pub fn pred_h_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
        unsafe {
            highbd_h_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
        }
    }

    pub fn pred_v_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
        unsafe {
            highbd_v_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
        }
    }

    fn do_dc_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>) {
        let (above, left, mut o1, mut o2) = setup_pred(ra);

        pred_dc_4x4(&mut o1, 32, &above[..4], &left[..4]);
        pred_dc(&mut o2, 32, &above[..4], &left[..4]);

        (o1, o2)
    }

    fn do_h_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>) {
        let (above, left, mut o1, mut o2) = setup_pred(ra);

        pred_h_4x4(&mut o1, 32, &above[..4], &left[..4]);
        pred_h(&mut o2, 32, &left[..4], 4);

        (o1, o2)
    }

    fn do_v_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>) {
        let (above, left, mut o1, mut o2) = setup_pred(ra);

        pred_v_4x4(&mut o1, 32, &above[..4], &left[..4]);
        pred_v(&mut o2, 32, &above[..4], 4);

        (o1, o2)
    }

    fn assert_same(o2: Vec<u16>) {
        for l in o2.chunks(32).take(4) {
            for v in l[..4].windows(2) {
                assert_eq!(v[0], v[1]);
            }
        }
    }

    #[test]
    fn pred_matches() {
        let mut ra = ChaChaRng::new_unseeded();
        for _ in 0..MAX_ITER {
            let (o1, o2) = do_dc_pred(&mut ra);
            assert_eq!(o1, o2);

            let (o1, o2) = do_h_pred(&mut ra);
            assert_eq!(o1, o2);

            let (o1, o2) = do_v_pred(&mut ra);
            assert_eq!(o1, o2);
        }
    }

    #[test]
    fn pred_same() {
        let mut ra = ChaChaRng::new_unseeded();
        for _ in 0..MAX_ITER {
            let (_, o2) = do_dc_pred(&mut ra);

            assert_same(o2)
        }
    }

    #[test]
    fn pred_max() {
        let max12bit = 4096 - 1;
        let above = [max12bit; 32];
        let left = [max12bit; 32];

        let mut o = vec![0u16; 32 * 32];

        pred_dc(&mut o, 32, &above[..4], &left[..4]);

        for l in o.chunks(32).take(4) {
            for v in l[..4].iter() {
                assert_eq!(*v, max12bit);
            }
        }

        pred_h(&mut o, 32, &left[..4], 4);

        for l in o.chunks(32).take(4) {
          for v in l[..4].iter() {
            assert_eq!(*v, max12bit);
          }
        }

        pred_v(&mut o, 32, &above[..4], 4);

        for l in o.chunks(32).take(4) {
          for v in l[..4].iter() {
            assert_eq!(*v, max12bit);
          }
        }
    }

    #[bench]
    fn native(b: &mut Bencher) {
        let mut ra = ChaChaRng::new_unseeded();
        let (above, left, _, mut o2) = setup_pred(&mut ra);

        b.iter(|| {
            pred_dc(&mut o2, 32, &above[..4], &left[..4]);
        })
    }

    #[bench]
    fn aom(b: &mut Bencher) {
        let mut ra = ChaChaRng::new_unseeded();
        let (above, left, _, mut o2) = setup_pred(&mut ra);

        b.iter(|| {
            pred_dc_4x4(&mut o2, 32, &above[..4], &left[..4]);
        })
    }
}
<commit_msg>Use Trait const to specialize pred_dc to 4x4<commit_after>use libc;

extern {
    #[cfg(test)]
    fn highbd_dc_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_dc_left_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    fn highbd_dc_top_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);
    #[cfg(test)]
    fn highbd_h_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
                           bh: libc::c_int, above: *const u16,
                           left: *const u16, bd: libc::c_int);

    #[cfg(test)]
    fn highbd_v_predictor(dst: *mut u16, stride: libc::ptrdiff_t, bw: libc::c_int,
        bh: libc::c_int, above: *const u16,
        left: *const u16, bd: libc::c_int);
}

pub fn pred_dc_128(output: &mut [u16], stride: usize) {
    for y in 0..4 {
        for x in 0..4 {
            output[y*stride+x] = 128;
        }
    }
}

pub fn pred_dc_left_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_left_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc_top_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    unsafe {
        highbd_dc_top_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
    }
}

pub fn pred_dc(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    let edges = left.iter().chain(above.iter());
    let bw = above.len();
    let bh = left.len();
    let len = (bw + bh) as u32;
    let avg = (edges.fold(0, |acc, &v| acc + v as u32) + (len >> 1)) / len;

    for line in output.chunks_mut(stride).take(bh) {
        for v in &mut line[..bw] {
            *v = avg as u16;
        }
    }
}

pub trait Dim {
    const W : usize;
    const H : usize;
}

pub struct Block4x4;

impl Dim for Block4x4 {
    const W : usize = 4;
    const H : usize = 4;
}

pub fn pred_dc_trait<D: Dim>(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
    let edges = left.iter().chain(above.iter());
    let bw = D::W;
    let bh = D::H;
    let len = (bw + bh) as u32;
    let avg = (edges.fold(0, |acc, &v| acc + v as u32) + (len >> 1)) / len;

    for line in output.chunks_mut(stride).take(bh) {
        for v in &mut line[..bw] {
            *v = avg as u16;
        }
    }
}

pub fn pred_h(output: &mut [u16], stride: usize, left: &[u16], bw: usize) {
  for (line, l) in output.chunks_mut(stride).zip(left) {
    for v in &mut line[..bw] {
      *v = *l;
    }
  }
}

pub fn pred_v(output: &mut [u16], stride: usize, above: &[u16], bh: usize) {
    let bw = above.len();
    for line in output.chunks_mut(stride).take(bh) {
        line[..bw].clone_from_slice(above)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rand::{ChaChaRng, Rng};
    use test::Bencher;

    const MAX_ITER: usize = 1000;

    fn setup_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>, Vec<u16>, Vec<u16>) {
        let output = vec![0u16; 32 * 32];
        let above: Vec<u16> = (0..32).map(|_| ra.gen()).collect();
        let left: Vec<u16> = (0..32).map(|_| ra.gen()).collect();

        let o1 = output.clone();
        let o2 = output.clone();

        (above, left, o1, o2)
    }

    fn pred_dc_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
        unsafe {
            highbd_dc_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
        }
    }

    pub fn pred_h_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
        unsafe {
            highbd_h_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
        }
    }

    pub fn pred_v_4x4(output: &mut [u16], stride: usize, above: &[u16], left: &[u16]) {
        unsafe {
            highbd_v_predictor(output.as_mut_ptr(), stride as libc::ptrdiff_t, 4, 4, above.as_ptr(), left.as_ptr(), 8);
        }
    }

    fn do_dc_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>) {
        let (above, left, mut o1, mut o2) = setup_pred(ra);

        pred_dc_4x4(&mut o1, 32, &above[..4], &left[..4]);
        pred_dc(&mut o2, 32, &above[..4], &left[..4]);

        (o1, o2)
    }

    fn do_h_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>) {
        let (above, left, mut o1, mut o2) = setup_pred(ra);

        pred_h_4x4(&mut o1, 32, &above[..4], &left[..4]);
        pred_h(&mut o2, 32, &left[..4], 4);

        (o1, o2)
    }

    fn do_v_pred(ra: &mut ChaChaRng) -> (Vec<u16>, Vec<u16>) {
        let (above, left, mut o1, mut o2) = setup_pred(ra);

        pred_v_4x4(&mut o1, 32, &above[..4], &left[..4]);
        pred_v(&mut o2, 32, &above[..4], 4);

        (o1, o2)
    }

    fn assert_same(o2: Vec<u16>) {
        for l in o2.chunks(32).take(4) {
            for v in l[..4].windows(2) {
                assert_eq!(v[0], v[1]);
            }
        }
    }

    #[test]
    fn pred_matches() {
        let mut ra = ChaChaRng::new_unseeded();
        for _ in 0..MAX_ITER {
            let (o1, o2) = do_dc_pred(&mut ra);
            assert_eq!(o1, o2);

            let (o1, o2) = do_h_pred(&mut ra);
            assert_eq!(o1, o2);

            let (o1, o2) = do_v_pred(&mut ra);
            assert_eq!(o1, o2);
        }
    }

    #[test]
    fn pred_same() {
        let mut ra = ChaChaRng::new_unseeded();
        for _ in 0..MAX_ITER {
            let (_, o2) = do_dc_pred(&mut ra);

            assert_same(o2)
        }
    }

    #[test]
    fn pred_max() {
        let max12bit = 4096 - 1;
        let above = [max12bit; 32];
        let left = [max12bit; 32];

        let mut o = vec![0u16; 32 * 32];

        pred_dc(&mut o, 32, &above[..4], &left[..4]);

        for l in o.chunks(32).take(4) {
            for v in l[..4].iter() {
                assert_eq!(*v, max12bit);
            }
        }

        pred_h(&mut o, 32, &left[..4], 4);

        for l in o.chunks(32).take(4) {
          for v in l[..4].iter() {
            assert_eq!(*v, max12bit);
          }
        }

        pred_v(&mut o, 32, &above[..4], 4);

        for l in o.chunks(32).take(4) {
          for v in l[..4].iter() {
            assert_eq!(*v, max12bit);
          }
        }
    }

    #[bench]
    fn native(b: &mut Bencher) {
        let mut ra = ChaChaRng::new_unseeded();
        let (above, left, _, mut o2) = setup_pred(&mut ra);

        b.iter(|| {
            pred_dc(&mut o2, 32, &above[..4], &left[..4]);
        })
    }

    #[bench]
    fn aom(b: &mut Bencher) {
        let mut ra = ChaChaRng::new_unseeded();
        let (above, left, _, mut o2) = setup_pred(&mut ra);

        b.iter(|| {
            pred_dc_4x4(&mut o2, 32, &above[..4], &left[..4]);
        })
    }
}
<|endoftext|>