<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_upper_case_globals)]

use core_foundation::array::CFArrayRef;
use core_foundation::base::{CFRelease, CFRetain, CFType, CFTypeID, CFTypeRef, TCFType};
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
use core_foundation::number::{CFNumber, CFNumberRef};
use core_foundation::set::CFSetRef;
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::url::{CFURL, CFURLRef};
use core_graphics::base::CGFloat;

use std::mem;

/*
* CTFontTraits.h
*/
// actually, these are extern enums
pub type CTFontFormat = u32;
pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
pub const kCTFontFormatTrueType: CTFontFormat = 3;
pub const kCTFontFormatPostScript: CTFontFormat = 4;
pub const kCTFontFormatBitmap: CTFontFormat = 5;

pub const kCTFontClassMaskShift: u32 = 28;

pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = (1 << 0);
pub const kCTFontBoldTrait: CTFontSymbolicTraits = (1 << 1);
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = (1 << 5);
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = (1 << 6);
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = (1 << 10);
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = (1 << 11);
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = (1 << 12);
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = (15 << kCTFontClassMaskShift );

pub trait SymbolicTraitAccessors {
    fn is_italic(&self) -> bool;
    fn is_bold(&self) -> bool;
    fn is_expanded(&self) -> bool;
    fn is_condensed(&self) -> bool;
    fn is_monospace(&self) -> bool;
}

impl SymbolicTraitAccessors for CTFontSymbolicTraits {
    fn is_italic(&self) -> bool { (*self & kCTFontItalicTrait) != 0 }
    fn is_bold(&self) -> bool { (*self & kCTFontBoldTrait) != 0 }
    fn is_expanded(&self) -> bool { (*self & kCTFontExpandedTrait) != 0 }
    fn is_condensed(&self) -> bool { (*self & kCTFontCondensedTrait) != 0 }
    fn is_monospace(&self) -> bool { (*self & kCTFontMonoSpaceTrait) != 0 }
}

pub type CTFontStylisticClass = u32;
pub const kCTFontUnknownClass: CTFontStylisticClass = (0 << kCTFontClassMaskShift );
pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = (1 << kCTFontClassMaskShift );
pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = (2 << kCTFontClassMaskShift );
pub const kCTFontModernSerifsClass: CTFontStylisticClass = (3 << kCTFontClassMaskShift );
pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = (4 << kCTFontClassMaskShift );
pub const kCTFontSlabSerifsClass: CTFontStylisticClass = (5 << kCTFontClassMaskShift );
pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = (7 << kCTFontClassMaskShift );
pub const kCTFontSansSerifClass: CTFontStylisticClass = (8 << kCTFontClassMaskShift );
pub const kCTFontOrnamentalsClass: CTFontStylisticClass = (9 << kCTFontClassMaskShift );
pub const kCTFontScriptsClass: CTFontStylisticClass = (10 << kCTFontClassMaskShift );
pub const kCTFontSymbolicClass: CTFontStylisticClass = (12 << kCTFontClassMaskShift );

pub trait StylisticClassAccessors {
    fn is_serif(&self) -> bool;
    fn is_sans_serif(&self) -> bool;
    fn is_script(&self) -> bool;
    fn is_fantasy(&self) -> bool;
    fn is_symbols(&self) -> bool;
}

impl StylisticClassAccessors for CTFontStylisticClass {
    fn is_serif(&self) -> bool {
        let any_serif_class = kCTFontOldStyleSerifsClass
            | kCTFontTransitionalSerifsClass
            | kCTFontModernSerifsClass
            | kCTFontClarendonSerifsClass
            | kCTFontSlabSerifsClass
            | kCTFontFreeformSerifsClass;

        return (*self & any_serif_class) != 0;
    }

    fn is_sans_serif(&self) -> bool {
        return (*self & kCTFontSansSerifClass) != 0;
    }

    fn is_script(&self) -> bool {
        return (*self & kCTFontScriptsClass) != 0;
    }

    fn is_fantasy(&self) -> bool {
        return (*self & kCTFontOrnamentalsClass) != 0;
    }

    fn is_symbols(&self) -> bool {
        return (*self & kCTFontSymbolicClass) != 0;
    }
}

pub type CTFontAttributes = CFDictionary;

pub type CTFontTraits = CFDictionary;

pub trait TraitAccessors {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits;
    fn normalized_weight(&self) -> f64;
    fn normalized_width(&self) -> f64;
    fn normalized_slant(&self) -> f64;
}

trait TraitAccessorPrivate {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber;
}

impl TraitAccessorPrivate for CTFontTraits {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber {
        let cftype = self.get_CFType(mem::transmute(key));
        assert!(cftype.instance_of::<CFNumberRef,CFNumber>());
        TCFType::wrap_under_get_rule(mem::transmute(cftype.as_CFTypeRef()))
    }

}

impl TraitAccessors for CTFontTraits {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSymbolicTrait);
            number.to_i64().unwrap() as u32
        }
    }

    fn normalized_weight(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWeightTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_width(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWidthTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_slant(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSlantTrait);
            number.to_f64().unwrap()
        }
    }
}

/*
* CTFontDescriptor.h
*/
pub type CTFontOrientation = u32;
pub const kCTFontDefaultOrientation: CTFontOrientation = 0;
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2;

pub type CTFontPriority = u32;
pub const kCTFontPrioritySystem: CTFontPriority = 10000;
pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
pub const kCTFontPriorityComputer: CTFontPriority = 30000;
pub const kCTFontPriorityUser: CTFontPriority = 40000;
pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
pub const kCTFontPriorityProcess: CTFontPriority = 60000;

#[repr(C)]
struct __CTFontDescriptor;

pub type CTFontDescriptorRef = *const __CTFontDescriptor;

#[derive(Debug)]
pub struct CTFontDescriptor {
    obj: CTFontDescriptorRef,
}

impl Drop for CTFontDescriptor {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl TCFType<CTFontDescriptorRef> for CTFontDescriptor {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CTFontDescriptorRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CTFontDescriptorRef) -> CTFontDescriptor {
        let reference: CTFontDescriptorRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CTFontDescriptorRef) -> CTFontDescriptor {
        CTFontDescriptor {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CTFontDescriptorGetTypeID()
        }
    }
}

impl CTFontDescriptor {
    fn get_string_attribute(&self, attribute: CFStringRef) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.obj, attribute);
            if value.is_null() {
                return None
            }

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFStringRef,CFString>());
            let s: CFString = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(s.to_string())
        }
    }

}

impl CTFontDescriptor {
    pub fn family_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
        value.expect("A font2 must have a non-null font family name.")
    }

    pub fn font_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontNameAttribute);
        value.expect("A font must have a non-null name.")
    }

    pub fn style_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontStyleNameAttribute);
        value.expect("A font must have a non-null style name.")
    }

    pub fn display_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
        value.expect("A font must have a non-null display name.")
    }

    pub fn font_path(&self) -> String {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.obj, kCTFontURLAttribute);
            assert!(!value.is_null());

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFURLRef,CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            format!("{:?}", url)
        }
    }
}

pub fn new_from_attributes(attributes: &CFDictionary) -> CTFontDescriptor {
    unsafe {
        let result: CTFontDescriptorRef =
            CTFontDescriptorCreateWithAttributes(attributes.as_concrete_TypeRef());
        TCFType::wrap_under_create_rule(result)
    }
}

pub fn debug_descriptor(desc: &CTFontDescriptor) {
    println!("family: {}", desc.family_name());
    println!("name: {}", desc.font_name());
    println!("style: {}", desc.style_name());
    println!("display: {}", desc.display_name());
    println!("path: {}", desc.font_path());
    desc.show();
}

extern {
    /*
     * CTFontTraits.h
     */

    // font trait constants
    pub static kCTFontSymbolicTrait: CFStringRef;
    pub static kCTFontWeightTrait: CFStringRef;
    pub static kCTFontWidthTrait: CFStringRef;
    pub static kCTFontSlantTrait: CFStringRef;

    /*
     * CTFontDescriptor.h
     */

    // font attribute constants. Note that the name-related attributes
    // here are somewhat flaky. Servo creates CTFont instances and
    // then uses CTFontCopyName to get more fine-grained names.
    pub static kCTFontURLAttribute:                  CFStringRef; // value: CFURLRef
    pub static kCTFontNameAttribute:                 CFStringRef; // value: CFStringRef
    pub static kCTFontDisplayNameAttribute:          CFStringRef; // value: CFStringRef
    pub static kCTFontFamilyNameAttribute:           CFStringRef; // value: CFStringRef
    pub static kCTFontStyleNameAttribute:            CFStringRef; // value: CFStringRef
    pub static kCTFontTraitsAttribute:               CFStringRef;
    pub static kCTFontVariationAttribute:            CFStringRef;
    pub static kCTFontSizeAttribute:                 CFStringRef;
    pub static kCTFontMatrixAttribute:               CFStringRef;
    pub static kCTFontCascadeListAttribute:          CFStringRef;
    pub static kCTFontCharacterSetAttribute:         CFStringRef;
    pub static kCTFontLanguagesAttribute:            CFStringRef;
    pub static kCTFontBaselineAdjustAttribute:       CFStringRef;
    pub static kCTFontMacintoshEncodingsAttribute:   CFStringRef;
    pub static kCTFontFeaturesAttribute:             CFStringRef;
    pub static kCTFontFeatureSettingsAttribute:      CFStringRef;
    pub static kCTFontFixedAdvanceAttribute:         CFStringRef;
    pub static kCTFontOrientationAttribute:          CFStringRef;
    pub static kCTFontFormatAttribute:               CFStringRef;
    pub static kCTFontRegistrationScopeAttribute:    CFStringRef;
    pub static kCTFontPriorityAttribute:             CFStringRef;
    pub static kCTFontEnabledAttribute:              CFStringRef;

    pub fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef,
                                         attribute: CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
    pub fn CTFontDescriptorCopyLocalizedAttribute(descriptor: CTFontDescriptorRef,
                                                  attribute: CFStringRef,
                                                  language: *mut CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCreateCopyWithAttributes(original: CTFontDescriptorRef,
                                                    attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithFeature(original: CTFontDescriptorRef,
                                                 featureTypeIdentifier: CFNumberRef,
                                                 featureSelectorIdentifier: CFNumberRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithVariation(original: CTFontDescriptorRef,
                                                   variationIdentifier: CFNumberRef,
                                                   variationValue: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateMatchingFontDescriptor(descriptor: CTFontDescriptorRef,
                                                        mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithNameAndSize(name: CFStringRef, size: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorGetTypeID() -> CFTypeID;
}

extern {
    pub fn CTFontDescriptorCreateMatchingFontDescriptors(descriptor: CTFontDescriptorRef,
                                                         mandatoryAttributes: CFSetRef) -> CFArrayRef;
}
<commit_msg>Auto merge of #53 - jrmuizel:kcolor, r=jdm<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_upper_case_globals)]

use core_foundation::array::CFArrayRef;
use core_foundation::base::{CFRelease, CFRetain, CFType, CFTypeID, CFTypeRef, TCFType};
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
use core_foundation::number::{CFNumber, CFNumberRef};
use core_foundation::set::CFSetRef;
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::url::{CFURL, CFURLRef};
use core_graphics::base::CGFloat;

use std::mem;

/*
* CTFontTraits.h
*/
// actually, these are extern enums
pub type CTFontFormat = u32;
pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
pub const kCTFontFormatTrueType: CTFontFormat = 3;
pub const kCTFontFormatPostScript: CTFontFormat = 4;
pub const kCTFontFormatBitmap: CTFontFormat = 5;

pub const kCTFontClassMaskShift: u32 = 28;

pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = (1 << 0);
pub const kCTFontBoldTrait: CTFontSymbolicTraits = (1 << 1);
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = (1 << 5);
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = (1 << 6);
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = (1 << 10);
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = (1 << 11);
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = (1 << 12);
pub const kCTFontColorGlyphsTrait: CTFontSymbolicTraits = (1 << 13);
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = (15 << kCTFontClassMaskShift );

pub trait SymbolicTraitAccessors {
    fn is_italic(&self) -> bool;
    fn is_bold(&self) -> bool;
    fn is_expanded(&self) -> bool;
    fn is_condensed(&self) -> bool;
    fn is_monospace(&self) -> bool;
}

impl SymbolicTraitAccessors for CTFontSymbolicTraits {
    fn is_italic(&self) -> bool { (*self & kCTFontItalicTrait) != 0 }
    fn is_bold(&self) -> bool { (*self & kCTFontBoldTrait) != 0 }
    fn is_expanded(&self) -> bool { (*self & kCTFontExpandedTrait) != 0 }
    fn is_condensed(&self) -> bool { (*self & kCTFontCondensedTrait) != 0 }
    fn is_monospace(&self) -> bool { (*self & kCTFontMonoSpaceTrait) != 0 }
}

pub type CTFontStylisticClass = u32;
pub const kCTFontUnknownClass: CTFontStylisticClass = (0 << kCTFontClassMaskShift );
pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = (1 << kCTFontClassMaskShift );
pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = (2 << kCTFontClassMaskShift );
pub const kCTFontModernSerifsClass: CTFontStylisticClass = (3 << kCTFontClassMaskShift );
pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = (4 << kCTFontClassMaskShift );
pub const kCTFontSlabSerifsClass: CTFontStylisticClass = (5 << kCTFontClassMaskShift );
pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = (7 << kCTFontClassMaskShift );
pub const kCTFontSansSerifClass: CTFontStylisticClass = (8 << kCTFontClassMaskShift );
pub const kCTFontOrnamentalsClass: CTFontStylisticClass = (9 << kCTFontClassMaskShift );
pub const kCTFontScriptsClass: CTFontStylisticClass = (10 << kCTFontClassMaskShift );
pub const kCTFontSymbolicClass: CTFontStylisticClass = (12 << kCTFontClassMaskShift );

pub trait StylisticClassAccessors {
    fn is_serif(&self) -> bool;
    fn is_sans_serif(&self) -> bool;
    fn is_script(&self) -> bool;
    fn is_fantasy(&self) -> bool;
    fn is_symbols(&self) -> bool;
}

impl StylisticClassAccessors for CTFontStylisticClass {
    fn is_serif(&self) -> bool {
        let any_serif_class = kCTFontOldStyleSerifsClass
            | kCTFontTransitionalSerifsClass
            | kCTFontModernSerifsClass
            | kCTFontClarendonSerifsClass
            | kCTFontSlabSerifsClass
            | kCTFontFreeformSerifsClass;

        return (*self & any_serif_class) != 0;
    }

    fn is_sans_serif(&self) -> bool {
        return (*self & kCTFontSansSerifClass) != 0;
    }

    fn is_script(&self) -> bool {
        return (*self & kCTFontScriptsClass) != 0;
    }

    fn is_fantasy(&self) -> bool {
        return (*self & kCTFontOrnamentalsClass) != 0;
    }

    fn is_symbols(&self) -> bool {
        return (*self & kCTFontSymbolicClass) != 0;
    }
}

pub type CTFontAttributes = CFDictionary;

pub type CTFontTraits = CFDictionary;

pub trait TraitAccessors {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits;
    fn normalized_weight(&self) -> f64;
    fn normalized_width(&self) -> f64;
    fn normalized_slant(&self) -> f64;
}

trait TraitAccessorPrivate {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber;
}

impl TraitAccessorPrivate for CTFontTraits {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber {
        let cftype = self.get_CFType(mem::transmute(key));
        assert!(cftype.instance_of::<CFNumberRef,CFNumber>());
        TCFType::wrap_under_get_rule(mem::transmute(cftype.as_CFTypeRef()))
    }

}

impl TraitAccessors for CTFontTraits {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSymbolicTrait);
            number.to_i64().unwrap() as u32
        }
    }

    fn normalized_weight(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWeightTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_width(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWidthTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_slant(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSlantTrait);
            number.to_f64().unwrap()
        }
    }
}

/*
* CTFontDescriptor.h
*/
pub type CTFontOrientation = u32;
pub const kCTFontDefaultOrientation: CTFontOrientation = 0;
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2;

pub type CTFontPriority = u32;
pub const kCTFontPrioritySystem: CTFontPriority = 10000;
pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
pub const kCTFontPriorityComputer: CTFontPriority = 30000;
pub const kCTFontPriorityUser: CTFontPriority = 40000;
pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
pub const kCTFontPriorityProcess: CTFontPriority = 60000;

#[repr(C)]
struct __CTFontDescriptor;

pub type CTFontDescriptorRef = *const __CTFontDescriptor;

#[derive(Debug)]
pub struct CTFontDescriptor {
    obj: CTFontDescriptorRef,
}

impl Drop for CTFontDescriptor {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl TCFType<CTFontDescriptorRef> for CTFontDescriptor {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CTFontDescriptorRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CTFontDescriptorRef) -> CTFontDescriptor {
        let reference: CTFontDescriptorRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CTFontDescriptorRef) -> CTFontDescriptor {
        CTFontDescriptor {
            obj: obj,
        }
    }

    #[inline]
    fn type_id() -> CFTypeID {
        unsafe {
            CTFontDescriptorGetTypeID()
        }
    }
}

impl CTFontDescriptor {
    fn get_string_attribute(&self, attribute: CFStringRef) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.obj, attribute);
            if value.is_null() {
                return None
            }

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFStringRef,CFString>());
            let s: CFString = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(s.to_string())
        }
    }

}

impl CTFontDescriptor {
    pub fn family_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
        value.expect("A font2 must have a non-null font family name.")
    }

    pub fn font_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontNameAttribute);
        value.expect("A font must have a non-null name.")
    }

    pub fn style_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontStyleNameAttribute);
        value.expect("A font must have a non-null style name.")
    }

    pub fn display_name(&self) -> String {
        let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
        value.expect("A font must have a non-null display name.")
    }

    pub fn font_path(&self) -> String {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.obj, kCTFontURLAttribute);
            assert!(!value.is_null());

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFURLRef,CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            format!("{:?}", url)
        }
    }
}

pub fn new_from_attributes(attributes: &CFDictionary) -> CTFontDescriptor {
    unsafe {
        let result: CTFontDescriptorRef =
            CTFontDescriptorCreateWithAttributes(attributes.as_concrete_TypeRef());
        TCFType::wrap_under_create_rule(result)
    }
}

pub fn debug_descriptor(desc: &CTFontDescriptor) {
    println!("family: {}", desc.family_name());
    println!("name: {}", desc.font_name());
    println!("style: {}", desc.style_name());
    println!("display: {}", desc.display_name());
    println!("path: {}", desc.font_path());
    desc.show();
}

extern {
    /*
     * CTFontTraits.h
     */

    // font trait constants
    pub static kCTFontSymbolicTrait: CFStringRef;
    pub static kCTFontWeightTrait: CFStringRef;
    pub static kCTFontWidthTrait: CFStringRef;
    pub static kCTFontSlantTrait: CFStringRef;

    /*
     * CTFontDescriptor.h
     */

    // font attribute constants. Note that the name-related attributes
    // here are somewhat flaky. Servo creates CTFont instances and
    // then uses CTFontCopyName to get more fine-grained names.
    pub static kCTFontURLAttribute:                  CFStringRef; // value: CFURLRef
    pub static kCTFontNameAttribute:                 CFStringRef; // value: CFStringRef
    pub static kCTFontDisplayNameAttribute:          CFStringRef; // value: CFStringRef
    pub static kCTFontFamilyNameAttribute:           CFStringRef; // value: CFStringRef
    pub static kCTFontStyleNameAttribute:            CFStringRef; // value: CFStringRef
    pub static kCTFontTraitsAttribute:               CFStringRef;
    pub static kCTFontVariationAttribute:            CFStringRef;
    pub static kCTFontSizeAttribute:                 CFStringRef;
    pub static kCTFontMatrixAttribute:               CFStringRef;
    pub static kCTFontCascadeListAttribute:          CFStringRef;
    pub static kCTFontCharacterSetAttribute:         CFStringRef;
    pub static kCTFontLanguagesAttribute:            CFStringRef;
    pub static kCTFontBaselineAdjustAttribute:       CFStringRef;
    pub static kCTFontMacintoshEncodingsAttribute:   CFStringRef;
    pub static kCTFontFeaturesAttribute:             CFStringRef;
    pub static kCTFontFeatureSettingsAttribute:      CFStringRef;
    pub static kCTFontFixedAdvanceAttribute:         CFStringRef;
    pub static kCTFontOrientationAttribute:          CFStringRef;
    pub static kCTFontFormatAttribute:               CFStringRef;
    pub static kCTFontRegistrationScopeAttribute:    CFStringRef;
    pub static kCTFontPriorityAttribute:             CFStringRef;
    pub static kCTFontEnabledAttribute:              CFStringRef;

    pub fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef,
                                         attribute: CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
    pub fn CTFontDescriptorCopyLocalizedAttribute(descriptor: CTFontDescriptorRef,
                                                  attribute: CFStringRef,
                                                  language: *mut CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCreateCopyWithAttributes(original: CTFontDescriptorRef,
                                                    attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithFeature(original: CTFontDescriptorRef,
                                                 featureTypeIdentifier: CFNumberRef,
                                                 featureSelectorIdentifier: CFNumberRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithVariation(original: CTFontDescriptorRef,
                                                   variationIdentifier: CFNumberRef,
                                                   variationValue: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateMatchingFontDescriptor(descriptor: CTFontDescriptorRef,
                                                        mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithNameAndSize(name: CFStringRef, size: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorGetTypeID() -> CFTypeID;
}

extern {
    pub fn CTFontDescriptorCreateMatchingFontDescriptors(descriptor: CTFontDescriptorRef,
                                                         mandatoryAttributes: CFSetRef) -> CFArrayRef;
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::u16;
use std::fmt;
use std::default::Default;

use super::{Frame, FrameBuilder};

bitflags! {
    flags OpCode: u8 {
        const CONTINUATION  = 0b0000_0000,
        const TEXT          = 0b0000_0001,
        const BINARY        = 0b0000_0010,
        const CLOSE         = 0b0000_1000,
        const PING          = 0b0000_1001,
        const PONG          = 0b0000_1010
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum FrameType {
    Control,
    Data
}

#[derive(Clone, PartialEq, Eq)]
pub enum OpType {
    Continuation,
    Text,
    Binary,
    Close,
    Ping,
    Pong
}

#[derive(Clone)]
struct Header {
    op_code: OpCode,
    mask: bool,
    payload_len: u64,
    masking_key: [u8; 4]
}

#[derive(Clone)]
struct Payload {
    data: Vec<u8>
}

#[derive(Clone)]
pub struct WebSocketFrame {
    frame_type: FrameType,
    header: Header,
    payload: Payload
}

#[derive(Clone)]
pub struct WebSocketFrameBuilder;
impl FrameBuilder for WebSocketFrameBuilder {
    fn from_bytes(buf: &mut Vec<u8>) -> Option<Box<Frame>> {
        if buf.len() < 5 {
            trace!("Buffer length is less than 5, not worth trying...");
            return None;
        }

        let mut frame: WebSocketFrame = Default::default();

        // OpCode and FrameType
        const FIN_CLEAR_MASK: u8 = 0b0000_1111;
        let op_byte = buf[0] & FIN_CLEAR_MASK;
        match OpCode::from_bits(op_byte) {
            Some(op_code) => {
                if op_code == CONTINUATION {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = CONTINUATION;
                } else if op_code == TEXT {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = TEXT;
                } else if op_code == BINARY {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = BINARY;
                } else if op_code == CLOSE {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = CLOSE;
                } else if op_code == PING {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = PING;
                } else if op_code == PONG {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = PONG;
                } else {
                    unreachable!();
                }
            }
            None => {
                error!("Invalid OpCode bits: {:#b}", buf[0]);
                return None;
            }
        }

        trace!("Frame info:   Type: {} | OpType: {}", frame.frame_type, frame.op_type());

        // Payload masked (If from client, must always be true)
        let mask_bit = 0b1000_0000 & buf[1];
        frame.header.mask = mask_bit > 0;

        trace!("Frame masked: {}", frame.header.mask);

        // Payload data length
        let mut next_offset: usize = 2;
        let payload_len = 0b0111_1111 & buf[1];
        if payload_len <= 125 {
            frame.header.payload_len = payload_len as u64;
        } else if payload_len == 126 {
            let mut len = (buf[2] as u16) << 8;
            len |= buf[3] as u16;
            frame.header.payload_len = len as u64;
            next_offset = 4;
        } else {
            // We don't want to cause a panic
            if buf.len() < 10 {
                trace!("Not enough payload to continue reading payload length");
                return None;
            }

            let mut len = (buf[2] as u64) << 56;
            len |= (buf[3] as u64) << 48;
            len |= (buf[4] as u64) << 40;
            len |= (buf[5] as u64) << 32;
            len |= (buf[6] as u64) << 24;
            len |= (buf[7] as u64) << 16;
            len |= (buf[8] as u64) << 8;
            len |= buf[9] as u64;
            frame.header.payload_len = len;
            next_offset = 10;
        }

        trace!("Payload length: {}", frame.header.payload_len);

        // Optional masking key
        if frame.header.mask {
            if buf.len() <= next_offset + 4 {
                trace!("Payload masked, not enough in buffer to read masking key");
                return None;
            }
            frame.header.masking_key[0] = buf[next_offset];
            frame.header.masking_key[1] = buf[next_offset + 1];
            frame.header.masking_key[2] = buf[next_offset + 2];
            frame.header.masking_key[3] = buf[next_offset + 3];
            next_offset += 4;
        }

        if buf.len() < next_offset + frame.header.payload_len as usize {
            trace!("Not enough in buffer to read payload");
            return None;
        }

        // Payload data
        let len = frame.header.payload_len as usize;
        frame.payload.data.extend_from_slice(&buf[next_offset..len]);

        trace!("Read complete");

        return Some(Box::new(frame));
    }
}

impl WebSocketFrame {
    pub fn new(buf: &[u8], frame_type: FrameType, op_type: OpType) -> WebSocketFrame {
        WebSocketFrame {
            frame_type: frame_type,
            header: Header {
                op_code: match op_type {
                    OpType::Continuation => CONTINUATION,
                    OpType::Text => TEXT,
                    OpType::Binary => BINARY,
                    OpType::Close => CLOSE,
                    OpType::Ping => PING,
                    OpType::Pong => PONG,
                },
                mask: false,
                payload_len: buf.len() as u64,
                masking_key: [0u8; 4]
            },
            payload: Payload {
                data: buf.to_vec()
            }
        }
    }

    pub fn op_type(&self) -> OpType {
        match self.header.op_code {
            CONTINUATION => OpType::Continuation,
            TEXT => OpType::Text,
            BINARY => OpType::Binary,
            CLOSE => OpType::Close,
            PING => OpType::Ping,
            PONG => OpType::Pong,
            _ => unreachable!()
        }
    }

    pub fn frame_type(&self) -> FrameType {
        self.frame_type.clone()
    }

    pub fn is_masked(&self) -> bool {
        self.header.mask
    }

    pub fn payload_unmasked(&self) -> Vec<u8> {
        let len = self.payload.data.len();
        let mut buf = Vec::<u8>::with_capacity(len);
        for x in 0..len {
            buf.push(self.payload.data[x] ^ self.header.masking_key[x % 4]);
        }

        buf
    }
}

impl Frame for WebSocketFrame {
    fn payload(&self) -> Vec<u8> {
        if self.header.mask {
            self.payload_unmasked()
        } else {
            self.payload.data.clone()
        }
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut buf = Vec::<u8>::with_capacity(self.len_as_vec());

        // OpCode
        buf.push(self.header.op_code.bits());

        // Mask and Payload len
        let mask_bit: u8 = if self.header.mask {
            0b1000_000
        } else {
            0b0000_000
        };
        let next_7_bits: u8 = if self.header.payload_len <= 125 {
            self.header.payload_len as u8
        } else if self.header.payload_len <= u16::MAX as u64 {
            126u8
        } else {
            127u8
        };
        let next_byte: u8 = mask_bit & next_7_bits;
        buf.push(next_byte);

        // Optional payload len
        if next_byte == 126 {
            buf.push(((self.header.payload_len as u16) >> 8) as u8);
            buf.push(self.header.payload_len as u8);
        } else if next_byte == 127 {
            buf.push((self.header.payload_len >> 56) as u8);
            buf.push((self.header.payload_len >> 48) as u8);
            buf.push((self.header.payload_len >> 40) as u8);
            buf.push((self.header.payload_len >> 32) as u8);
            buf.push((self.header.payload_len >> 24) as u8);
            buf.push((self.header.payload_len >> 16) as u8);
            buf.push((self.header.payload_len >> 8) as u8);
            buf.push(self.header.payload_len as u8);
        }

        // Optional masking key
        if self.header.mask {
            buf.push(self.header.masking_key[0]);
            buf.push(self.header.masking_key[1]);
            buf.push(self.header.masking_key[2]);
            buf.push(self.header.masking_key[3]);
        }

        // Payload data
        buf.extend_from_slice(&self.payload.data[..]);

        buf
    }

    fn len_as_vec(&self) -> usize {
        let mut len = 0usize;

        // OpCode
        len += 1;

        // Mask and paylaod length
        len += 1;

        // Extended Payload length
        if self.header.payload_len > 125 && self.header.payload_len < u16::MAX as u64 {
            len += 2;
        } else if self.header.payload_len > u16::MAX as u64 {
            len += 8;
        }

        // Optional masking key
        if self.header.mask {
            len += 4;
        }

        // Payload data
        len += self.header.payload_len as usize;

        len
    }

    fn as_mut_raw_erased(&self) -> *mut () {
        let dup = Box::new(self.clone());
        return Box::into_raw(dup) as *mut _ as *mut ();
    }
}

impl Default for WebSocketFrame {
    fn default() -> WebSocketFrame {
        WebSocketFrame {
            frame_type: FrameType::Control,
            header: Header {
                op_code: CONTINUATION,
                mask: false,
                payload_len: 0u64,
                masking_key: [0u8; 4]
            },
            payload: Payload {
                data: Vec::<u8>::new()
            }
        }
    }
}

impl fmt::Debug for FrameType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FrameType::Control => write!(f, "FrameType::Control"),
            FrameType::Data => write!(f, "FrameType::Data")
        }
    }
}

impl fmt::Display for FrameType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FrameType::Control => write!(f, "FrameType::Control"),
            FrameType::Data => write!(f, "FrameType::Data")
        }
    }
}

impl fmt::Debug for OpType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpType::Continuation => write!(f, "OpType::Continuation"),
            OpType::Text => write!(f, "OpType::Text"),
            OpType::Binary => write!(f, "OpType::Binary"),
            OpType::Close => write!(f, "OpType::Close"),
            OpType::Ping => write!(f, "OpType::Ping"),
            OpType::Pong => write!(f, "OpType::Pong"),
        }
    }
}

impl fmt::Display for OpType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpType::Continuation => write!(f, "OpType::Continuation"),
            OpType::Text => write!(f, "OpType::Text"),
            OpType::Binary => write!(f, "OpType::Binary"),
            OpType::Close => write!(f, "OpType::Close"),
            OpType::Ping => write!(f, "OpType::Ping"),
            OpType::Pong => write!(f, "OpType::Pong"),
        }
    }
}
<commit_msg>I think weboscket framing is actually correct now.<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::{u16, fmt, mem};
use std::default::Default;

use super::{Frame, FrameBuilder};

bitflags! {
    flags OpCode: u8 {
        const CONTINUATION  = 0b0000_0000,
        const TEXT          = 0b0000_0001,
        const BINARY        = 0b0000_0010,
        const CLOSE         = 0b0000_1000,
        const PING          = 0b0000_1001,
        const PONG          = 0b0000_1010
    }
}

#[derive(Clone, PartialEq, Eq)]
pub enum FrameType {
    Control,
    Data
}

#[derive(Clone, PartialEq, Eq)]
pub enum OpType {
    Continuation,
    Text,
    Binary,
    Close,
    Ping,
    Pong
}

#[derive(Clone)]
struct Header {
    op_code: OpCode,
    mask: bool,
    payload_len: u64,
    masking_key: [u8; 4]
}

#[derive(Clone)]
struct Payload {
    data: Vec<u8>
}

#[derive(Clone)]
pub struct WebSocketFrame {
    frame_type: FrameType,
    header: Header,
    payload: Payload
}

#[derive(Clone)]
pub struct WebSocketFrameBuilder;
impl FrameBuilder for WebSocketFrameBuilder {
    fn from_bytes(buf: &mut Vec<u8>) -> Option<Box<Frame>> {
        if buf.len() < 5 {
            trace!("Buffer length is less than 5, not worth trying...");
            return None;
        }

        let mut frame: WebSocketFrame = Default::default();

        // OpCode and FrameType
        const FIN_CLEAR_MASK: u8 = 0b0000_1111;
        let op_byte = buf[0] & FIN_CLEAR_MASK;
        match OpCode::from_bits(op_byte) {
            Some(op_code) => {
                if op_code == CONTINUATION {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = CONTINUATION;
                } else if op_code == TEXT {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = TEXT;
                } else if op_code == BINARY {
                    frame.frame_type = FrameType::Data;
                    frame.header.op_code = BINARY;
                } else if op_code == CLOSE {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = CLOSE;
                } else if op_code == PING {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = PING;
                } else if op_code == PONG {
                    frame.frame_type = FrameType::Control;
                    frame.header.op_code = PONG;
                } else {
                    unreachable!();
                }
            }
            None => {
                error!("Invalid OpCode bits: {:#b}", buf[0]);
                return None;
            }
        }

        trace!("Frame info:   Type: {} | OpType: {}", frame.frame_type, frame.op_type());

        // Payload masked (If from client, must always be true)
        let mask_bit = 0b1000_0000 & buf[1];
        frame.header.mask = mask_bit > 0;

        trace!("Frame masked: {}", frame.header.mask);

        // Payload data length
        let payload_len = 0b0111_1111 & buf[1];
        let mut next_offset: usize = 2;
        if payload_len <= 125 {
            frame.header.payload_len = payload_len as u64;
        } else if payload_len == 126 {
            let mut len = (buf[2] as u16) << 8;
            len |= buf[3] as u16;
            frame.header.payload_len = len as u64;
            next_offset = 4;
        } else {
            // We don't want to cause a panic
            if buf.len() < 10 {
                trace!("Not enough payload to continue reading payload length");
                return None;
            }

            let mut len = (buf[2] as u64) << 56;
            len |= (buf[3] as u64) << 48;
            len |= (buf[4] as u64) << 40;
            len |= (buf[5] as u64) << 32;
            len |= (buf[6] as u64) << 24;
            len |= (buf[7] as u64) << 16;
            len |= (buf[8] as u64) << 8;
            len |= buf[9] as u64;
            frame.header.payload_len = len;
            next_offset = 10;
        }

        trace!("Payload length: {}", frame.header.payload_len);

        // Optional masking key
        if frame.header.mask {
            if buf.len() <= next_offset + 4 {
                trace!("Payload masked, not enough in buffer to read masking key");
                return None;
            }
            frame.header.masking_key[0] = buf[next_offset];
            frame.header.masking_key[1] = buf[next_offset + 1];
            frame.header.masking_key[2] = buf[next_offset + 2];
            frame.header.masking_key[3] = buf[next_offset + 3];
            next_offset += 4;
        }

        if buf.len() < next_offset + frame.header.payload_len as usize {
            trace!("Not enough in buffer to read payload");
            return None;
        }

        // Payload data
        let len = frame.header.payload_len as usize;
        frame.payload.data.extend_from_slice(&buf[next_offset..(len + next_offset)]);

        // Remove from buffer
        let mut remainder = Vec::<u8>::with_capacity(buf.len() - frame.len_as_vec());
        remainder.extend_from_slice(&buf[frame.len_as_vec()..buf.len()]);
        mem::swap(buf, &mut remainder);

        return Some(Box::new(frame));
    }
}

impl WebSocketFrame {
    pub fn new(buf: &[u8], frame_type: FrameType, op_type: OpType) -> WebSocketFrame {
        WebSocketFrame {
            frame_type: frame_type,
            header: Header {
                op_code: match op_type {
                    OpType::Continuation => CONTINUATION,
                    OpType::Text => TEXT,
                    OpType::Binary => BINARY,
                    OpType::Close => CLOSE,
                    OpType::Ping => PING,
                    OpType::Pong => PONG,
                },
                mask: false,
                payload_len: buf.len() as u64,
                masking_key: [0u8; 4]
            },
            payload: Payload {
                data: buf.to_vec()
            }
        }
    }

    pub fn op_type(&self) -> OpType {
        match self.header.op_code {
            CONTINUATION => OpType::Continuation,
            TEXT => OpType::Text,
            BINARY => OpType::Binary,
            CLOSE => OpType::Close,
            PING => OpType::Ping,
            PONG => OpType::Pong,
            _ => unreachable!()
        }
    }

    pub fn frame_type(&self) -> FrameType {
        self.frame_type.clone()
    }

    pub fn is_masked(&self) -> bool {
        self.header.mask
    }

    pub fn payload_unmasked(&self) -> Vec<u8> {
        let len = self.payload.data.len();
        let mut buf = Vec::<u8>::with_capacity(len);
        for x in 0..len {
            buf.push(self.payload.data[x] ^ self.header.masking_key[x % 4]);
        }

        buf
    }
}

impl Frame for WebSocketFrame {
    fn payload(&self) -> Vec<u8> {
        if self.header.mask {
            self.payload_unmasked()
        } else {
            self.payload.data.clone()
        }
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut buf = Vec::<u8>::with_capacity(self.len_as_vec());

        // OpCode
        buf.push(self.header.op_code.bits());

        // Mask and Payload len
        let mask_bit: u8 = if self.header.mask {
            0b1000_000
        } else {
            0b0000_000
        };
        let next_7_bits: u8 = if self.header.payload_len <= 125 {
            self.header.payload_len as u8
        } else if self.header.payload_len <= u16::MAX as u64 {
            126u8
        } else {
            127u8
        };
        let next_byte: u8 = mask_bit & next_7_bits;
        buf.push(next_byte);

        // Optional payload len
        if next_byte == 126 {
            buf.push(((self.header.payload_len as u16) >> 8) as u8);
            buf.push(self.header.payload_len as u8);
        } else if next_byte == 127 {
            buf.push((self.header.payload_len >> 56) as u8);
            buf.push((self.header.payload_len >> 48) as u8);
            buf.push((self.header.payload_len >> 40) as u8);
            buf.push((self.header.payload_len >> 32) as u8);
            buf.push((self.header.payload_len >> 24) as u8);
            buf.push((self.header.payload_len >> 16) as u8);
            buf.push((self.header.payload_len >> 8) as u8);
            buf.push(self.header.payload_len as u8);
        }

        // Optional masking key
        if self.header.mask {
            buf.push(self.header.masking_key[0]);
            buf.push(self.header.masking_key[1]);
            buf.push(self.header.masking_key[2]);
            buf.push(self.header.masking_key[3]);
        }

        // Payload data
        buf.extend_from_slice(&self.payload.data[..]);

        buf
    }

    fn len_as_vec(&self) -> usize {
        let mut len = 0usize;

        // OpCode
        len += 1;

        // Mask and paylaod length
        len += 1;

        // Extended Payload length
        if self.header.payload_len > 125 && self.header.payload_len < u16::MAX as u64 {
            len += 2;
        } else if self.header.payload_len > u16::MAX as u64 {
            len += 8;
        }

        // Optional masking key
        if self.header.mask {
            len += 4;
        }

        // Payload data
        len += self.header.payload_len as usize;

        len
    }

    fn as_mut_raw_erased(&self) -> *mut () {
        let dup = Box::new(self.clone());
        return Box::into_raw(dup) as *mut _ as *mut ();
    }
}

impl Default for WebSocketFrame {
    fn default() -> WebSocketFrame {
        WebSocketFrame {
            frame_type: FrameType::Control,
            header: Header {
                op_code: CONTINUATION,
                mask: false,
                payload_len: 0u64,
                masking_key: [0u8; 4]
            },
            payload: Payload {
                data: Vec::<u8>::new()
            }
        }
    }
}

impl fmt::Debug for FrameType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FrameType::Control => write!(f, "FrameType::Control"),
            FrameType::Data => write!(f, "FrameType::Data")
        }
    }
}

impl fmt::Display for FrameType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FrameType::Control => write!(f, "FrameType::Control"),
            FrameType::Data => write!(f, "FrameType::Data")
        }
    }
}

impl fmt::Debug for OpType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpType::Continuation => write!(f, "OpType::Continuation"),
            OpType::Text => write!(f, "OpType::Text"),
            OpType::Binary => write!(f, "OpType::Binary"),
            OpType::Close => write!(f, "OpType::Close"),
            OpType::Ping => write!(f, "OpType::Ping"),
            OpType::Pong => write!(f, "OpType::Pong"),
        }
    }
}

impl fmt::Display for OpType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            OpType::Continuation => write!(f, "OpType::Continuation"),
            OpType::Text => write!(f, "OpType::Text"),
            OpType::Binary => write!(f, "OpType::Binary"),
            OpType::Close => write!(f, "OpType::Close"),
            OpType::Ping => write!(f, "OpType::Ping"),
            OpType::Pong => write!(f, "OpType::Pong"),
        }
    }
}
<|endoftext|>


<commit_before>use crossbeam_channel as channel;
use game::constants::VIEW_DISTANCE;
use shaders::Position;
use specs;
use specs::prelude::WriteStorage;

#[derive(Clone, Debug)]
pub struct CameraInputState {
  pub distance: f32,
  pub movement: Position,
}

impl CameraInputState {
  pub fn new() -> CameraInputState {
    CameraInputState {
      distance: VIEW_DISTANCE,
      movement: Position::origin(),
    }
  }
}

impl Default for CameraInputState {
  fn default() -> CameraInputState {
    CameraInputState::new()
  }
}

impl specs::prelude::Component for CameraInputState {
  type Storage = specs::storage::HashMapStorage<CameraInputState>;
}

#[derive(Debug)]
pub enum CameraControl {
  ZoomOut,
  ZoomIn,
  ZoomStop,
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CameraControlSystem {
  queue: channel::Receiver<CameraControl>,
  zoom_level: Option<f32>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CameraControlSystem {
  pub fn new() -> (CameraControlSystem, channel::Sender<CameraControl>) {
    let (tx, rx) = channel::unbounded();
    (CameraControlSystem {
      queue: rx,
      zoom_level: None,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::prelude::System<'a> for CameraControlSystem {
  type SystemData = (WriteStorage<'a, CameraInputState>);
  fn run(&mut self, mut map_input: Self::SystemData) {
    use specs::join::Join;

    while let Some(control) = self.queue.try_recv() {
      match control {
        CameraControl::ZoomIn => self.zoom_level = Some(2.0),
        CameraControl::ZoomOut => self.zoom_level = Some(-2.0),
        CameraControl::ZoomStop => self.zoom_level = None,
        _ => (),
      }
    }
    if let Some(zoom) = self.zoom_level {
      for m in (&mut map_input).join() {
        if m.distance > 200.0 && zoom < 0.0 || m.distance < 1000.0 && zoom > 0.0 {
          m.distance += zoom;
        }
      }
    }
  }
}
<commit_msg>Limit max zoom level<commit_after>use crossbeam_channel as channel;
use game::constants::VIEW_DISTANCE;
use shaders::Position;
use specs;
use specs::prelude::WriteStorage;

#[derive(Clone, Debug)]
pub struct CameraInputState {
  pub distance: f32,
  pub movement: Position,
}

impl CameraInputState {
  pub fn new() -> CameraInputState {
    CameraInputState {
      distance: VIEW_DISTANCE,
      movement: Position::origin(),
    }
  }
}

impl Default for CameraInputState {
  fn default() -> CameraInputState {
    CameraInputState::new()
  }
}

impl specs::prelude::Component for CameraInputState {
  type Storage = specs::storage::HashMapStorage<CameraInputState>;
}

#[derive(Debug)]
pub enum CameraControl {
  ZoomOut,
  ZoomIn,
  ZoomStop,
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CameraControlSystem {
  queue: channel::Receiver<CameraControl>,
  zoom_level: Option<f32>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CameraControlSystem {
  pub fn new() -> (CameraControlSystem, channel::Sender<CameraControl>) {
    let (tx, rx) = channel::unbounded();
    (CameraControlSystem {
      queue: rx,
      zoom_level: None,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::prelude::System<'a> for CameraControlSystem {
  type SystemData = (WriteStorage<'a, CameraInputState>);
  fn run(&mut self, mut map_input: Self::SystemData) {
    use specs::join::Join;

    while let Some(control) = self.queue.try_recv() {
      match control {
        CameraControl::ZoomIn => self.zoom_level = Some(2.0),
        CameraControl::ZoomOut => self.zoom_level = Some(-2.0),
        CameraControl::ZoomStop => self.zoom_level = None,
        _ => (),
      }
    }
    if let Some(zoom) = self.zoom_level {
      for m in (&mut map_input).join() {
        if m.distance > 200.0 && zoom < 0.0 || m.distance < 600.0 && zoom > 0.0 {
          m.distance += zoom;
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Hamming_numbers
extern crate num;
use num::bigint::{BigUint, ToBigUint};
use std::cmp::min;
use std::num::{One, one};
use std::collections::{RingBuf, Deque};

// needed because hamming_numbers_alt uses this as a library
#[allow(dead_code)]
#[cfg(not(test))]
fn main() {
    // capacity of the queue currently needs to be a power of 2 because of a bug with RingBuf
    let hamming : Hamming<BigUint> = Hamming::new(128);

    for (idx, h) in hamming.enumerate().take(1_000_000) {
        match idx + 1 {
            1...20 => print!("{} ", h.to_biguint().unwrap()),
            i @ 1691 | i @ 1000000 => println!("\n{}th number: {}", i, h.to_biguint().unwrap()),
            _ =>  continue
        }
    }
}
//representing a Hamming number as a BigUint
impl HammingNumber for BigUint {
    // returns the multipliers 2, 3 and 5 in the representation for the HammingNumber
    fn multipliers()-> (BigUint, BigUint, BigUint) {
        (2u.to_biguint().unwrap(),
        3u.to_biguint().unwrap(),
        5u.to_biguint().unwrap())
    }
}

/// representation of a Hamming number
/// allows to abstract on how the hamming number is stored
/// i.e. as BigUint directly or just as the powers of 2, 3 and 5 used to build it
pub trait HammingNumber : Eq + Ord + ToBigUint + Mul<Self, Self> + One {
    fn multipliers() -> (Self, Self, Self);
}

/// Hamming numbers are multiples of 2, 3 or 5.
///
/// We keep them on three queues and extract the lowest (leftmost) value from
/// the three queues at each iteration.
pub struct Hamming<T> {
    // Using a RingBuf as a queue, push to the back, pop from the front
    q2: RingBuf<T>,
    q3: RingBuf<T>,
    q5: RingBuf<T>
}

impl<T: HammingNumber> Hamming<T> {
    /// Static constructor method
    /// `n` initializes the capacity of the queues
    pub fn new(n: uint) -> Hamming<T> {
        let mut h = Hamming {
            q2: RingBuf::with_capacity(n),
            q3: RingBuf::with_capacity(n),
            q5: RingBuf::with_capacity(n)
        };

        h.q2.push(one());
        h.q3.push(one());
        h.q5.push(one());

        h
    }

    /// Pushes the next multiple of `n` (x2, x3, x5) to the queues
    pub fn enqueue(&mut self, n: &T) {
        let (two, three, five) = HammingNumber::multipliers();
        self.q2.push(*n * two);
        self.q3.push(*n * three);
        self.q5.push(*n * five);
    }
}

// Implements the `Iterator` trait, so we can generate Hamming numbers lazily
impl<T: HammingNumber> Iterator<T> for Hamming<T> {
    // The core of the work is done in the `next` method.
    // We check which of the 3 queues has the lowest candidate and extract it
    // as the next Hamming number.
    fn next(&mut self) -> Option<T> {
        // Return `pop_targets` so the borrow from `front()` will be finished
        let (two, three, five) = match (self.q2.front(),
                                        self.q3.front(),
                                        self.q5.front()) {
            (Some(head2), Some(head3), Some(head5)) => {
                let n = min(head2, min(head3, head5));
                (head2 == n, head3 == n, head5 == n)
            },
            _ => unreachable!()
        };

        let h2 = if two { self.q2.pop_front() } else { None };
        let h3 = if three { self.q3.pop_front() } else { None };
        let h5 = if five { self.q5.pop_front() } else { None };

        match h2.or(h3).or(h5) {
            Some(n) => {
                self.enqueue(&n);
                Some(n)
            }
            None => unreachable!()
        }
    }
}

#[test]
fn create() {
    let mut h = Hamming::<BigUint>::new(5);
    h.q2.push(one::<BigUint>());
    h.q2.push(one::<BigUint>() * 3u.to_biguint().unwrap());

    assert_eq!(h.q2.pop_front().unwrap(), one::<BigUint>());
}

#[test]
fn try_enqueue() {
    let mut h = Hamming::<BigUint>::new(5);
    let (two, three, five) = HammingNumber::multipliers();
    h.enqueue(&one::<BigUint>());
    h.enqueue(&(&one::<BigUint>() * two));

    assert!(h.q2.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q3.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q5.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q2.pop_front().unwrap() == one::<BigUint>() * two);
    assert!(h.q3.pop_front().unwrap() == one::<BigUint>() * three);
    assert!(h.q5.pop_front().unwrap() == one::<BigUint>() * five);
 }

#[test]
fn hamming_iter() {
    let mut hamming = Hamming::<BigUint>::new(20);
    assert!(hamming.nth(19).unwrap().to_biguint() == 36u.to_biguint());
}

#[test]
fn hamming_iter_1million() {
    let mut hamming = Hamming::<BigUint>::new(128);
    // one-million-th hamming number has index 999_999 because indexes are zero-based
    assert_eq!(hamming.nth(999_999).unwrap().to_biguint(),
        from_str(
        "519312780448388736089589843750000000000000000000000000000000000000000000000000000000")
        );
}
<commit_msg>Removing slow test from Hamming numbers (still exists if you run main()).<commit_after>// http://rosettacode.org/wiki/Hamming_numbers
extern crate num;
use num::bigint::{BigUint, ToBigUint};
use std::cmp::min;
use std::num::{One, one};
use std::collections::{RingBuf, Deque};

// needed because hamming_numbers_alt uses this as a library
#[allow(dead_code)]
#[cfg(not(test))]
fn main() {
    static HAMMING_1_MILLION: &'static str =
"519312780448388736089589843750000000000000000000000000000000000000000000000000000000";
    // capacity of the queue currently needs to be a power of 2 because of a bug with RingBuf
    let hamming : Hamming<BigUint> = Hamming::new(128);

    for (idx, h) in hamming.enumerate().take(1_000_000) {
        match idx + 1 {
            1...20 => print!("{} ", h.to_biguint().unwrap()),
            i @ 1691 => println!("\n{}th number: {}", i, h.to_biguint().unwrap()),
            i @ 1000000 => {
                let n = h.to_biguint().unwrap();
                println!("\n{}th number: {}", i, n);
                assert_eq!(n, from_str(HAMMING_1_MILLION).unwrap())
            },
            _ =>  continue
        }
    }
}

//representing a Hamming number as a BigUint
impl HammingNumber for BigUint {
    // returns the multipliers 2, 3 and 5 in the representation for the HammingNumber
    fn multipliers()-> (BigUint, BigUint, BigUint) {
        (2u.to_biguint().unwrap(),
        3u.to_biguint().unwrap(),
        5u.to_biguint().unwrap())
    }
}

/// representation of a Hamming number
/// allows to abstract on how the hamming number is stored
/// i.e. as BigUint directly or just as the powers of 2, 3 and 5 used to build it
pub trait HammingNumber : Eq + Ord + ToBigUint + Mul<Self, Self> + One {
    fn multipliers() -> (Self, Self, Self);
}

/// Hamming numbers are multiples of 2, 3 or 5.
///
/// We keep them on three queues and extract the lowest (leftmost) value from
/// the three queues at each iteration.
pub struct Hamming<T> {
    // Using a RingBuf as a queue, push to the back, pop from the front
    q2: RingBuf<T>,
    q3: RingBuf<T>,
    q5: RingBuf<T>
}

impl<T: HammingNumber> Hamming<T> {
    /// Static constructor method
    /// `n` initializes the capacity of the queues
    pub fn new(n: uint) -> Hamming<T> {
        let mut h = Hamming {
            q2: RingBuf::with_capacity(n),
            q3: RingBuf::with_capacity(n),
            q5: RingBuf::with_capacity(n)
        };

        h.q2.push(one());
        h.q3.push(one());
        h.q5.push(one());

        h
    }

    /// Pushes the next multiple of `n` (x2, x3, x5) to the queues
    pub fn enqueue(&mut self, n: &T) {
        let (two, three, five) = HammingNumber::multipliers();
        self.q2.push(*n * two);
        self.q3.push(*n * three);
        self.q5.push(*n * five);
    }
}

// Implements the `Iterator` trait, so we can generate Hamming numbers lazily
impl<T: HammingNumber> Iterator<T> for Hamming<T> {
    // The core of the work is done in the `next` method.
    // We check which of the 3 queues has the lowest candidate and extract it
    // as the next Hamming number.
    fn next(&mut self) -> Option<T> {
        // Return `pop_targets` so the borrow from `front()` will be finished
        let (two, three, five) = match (self.q2.front(),
                                        self.q3.front(),
                                        self.q5.front()) {
            (Some(head2), Some(head3), Some(head5)) => {
                let n = min(head2, min(head3, head5));
                (head2 == n, head3 == n, head5 == n)
            },
            _ => unreachable!()
        };

        let h2 = if two { self.q2.pop_front() } else { None };
        let h3 = if three { self.q3.pop_front() } else { None };
        let h5 = if five { self.q5.pop_front() } else { None };

        match h2.or(h3).or(h5) {
            Some(n) => {
                self.enqueue(&n);
                Some(n)
            }
            None => unreachable!()
        }
    }
}

#[test]
fn create() {
    let mut h = Hamming::<BigUint>::new(5);
    h.q2.push(one::<BigUint>());
    h.q2.push(one::<BigUint>() * 3u.to_biguint().unwrap());

    assert_eq!(h.q2.pop_front().unwrap(), one::<BigUint>());
}

#[test]
fn try_enqueue() {
    let mut h = Hamming::<BigUint>::new(5);
    let (two, three, five) = HammingNumber::multipliers();
    h.enqueue(&one::<BigUint>());
    h.enqueue(&(&one::<BigUint>() * two));

    assert!(h.q2.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q3.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q5.pop_front().unwrap() == one::<BigUint>());
    assert!(h.q2.pop_front().unwrap() == one::<BigUint>() * two);
    assert!(h.q3.pop_front().unwrap() == one::<BigUint>() * three);
    assert!(h.q5.pop_front().unwrap() == one::<BigUint>() * five);
 }

#[test]
fn hamming_iter() {
    let mut hamming = Hamming::<BigUint>::new(20);
    assert!(hamming.nth(19).unwrap().to_biguint() == 36u.to_biguint());
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate transproblem;

use getopts::Options;
use transproblem::Transportation;
use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
use std::path::PathBuf;

#[derive(Debug)]
enum InputError {
    Io(io::Error),
    Parse(std::num::ParseIntError),
}

impl From<io::Error> for InputError {
    fn from(err: io::Error) -> InputError {
        InputError::Io(err)
    }
}

impl From<std::num::ParseIntError> for InputError {
    fn from(err: std::num::ParseIntError) -> InputError {
        InputError::Parse(err)
    }
}

fn file_input(file: &PathBuf) -> Result<(Vec<u64>, Vec<u64>, Vec<Vec<u64>>), InputError> {
    let mut f = BufReader::new(try!(File::open(file)));

    let mut a = String::new();
    try!(f.read_line(&mut a));
    let a: Vec<u64> = try!(a.split_whitespace()
                            .map(|number| number.parse())
                            .collect());

    let mut b = String::new();
    try!(f.read_line(&mut b));
    let b: Vec<u64> = try!(b.split_whitespace()
                            .map(|number| number.parse())
                            .collect());

    let lines: Vec<String> = try!(f.lines().collect());
    let c: Vec<Vec<u64>> = try!(lines.iter()
                                     .filter(|line| !line.is_empty())
                                     .map(|line| {
                                         line.split_whitespace()
                                             .map(|number| number.parse())
                                             .collect()
                                     })
                                     .collect());

    Ok((a, b, c))
}

fn console_input() -> Result<(Vec<u64>, Vec<u64>, Vec<Vec<u64>>), io::Error> {
    let mut a: Vec<u64>;
    let mut b: Vec<u64>;
    let mut c: Vec<Vec<u64>>;
    let mut buffer = String::new();

    println!("Введите количество поставщиков");
    loop {
        print!("A = ");
        try!(io::stdout().flush());
        buffer.clear();
        try!(io::stdin().read_line(&mut buffer));
        match buffer.trim().parse() {
            Ok(size) => {
                a = vec![0;size];
                break;
            }
            Err(_) => println!("Ошибка: количество поставщиков должно быть целым неотрицательным числом"),
        }
    }

    println!("Введите количество потребителей");
    loop {
        print!("B = ");
        try!(io::stdout().flush());
        buffer.clear();
        try!(io::stdin().read_line(&mut buffer));
        match buffer.trim().parse() {
            Ok(size) => {
                b = vec![0;size];
                break;
            }
            Err(_) => println!("Ошибка: количество потребителей должно быть целым неотрицательным числом"),
        }
    }

    println!("Введите количество груза у каждого поставщика");
    for i in 0..a.len() {
        loop {
            print!("a[{}] = ", i + 1);
            try!(io::stdout().flush());
            buffer.clear();
            try!(io::stdin().read_line(&mut buffer));
            match buffer.trim().parse() {
                Ok(amount) => {
                    a[i] = amount;
                    break;
                }
                Err(_) => println!("Ошибка: количество груза должно быть целым неотрицательным числом"),
            }
        }
    }

    println!("Введите количество заказоного груза у каждого потребителя");
    for i in 0..b.len() {
        loop {
            print!("b[{}] = ", i + 1);
            try!(io::stdout().flush());
            buffer.clear();
            try!(io::stdin().read_line(&mut buffer));
            match buffer.trim().parse() {
                Ok(amount) => {
                    b[i] = amount;
                    break;
                }
                Err(_) => println!("Ошибка: количество груза должно быть целым неотрицательным числом"),
            }
        }
    }

    println!("Введите стоимости перевозок");
    c = vec![vec![0;b.len()];a.len()];
    for i in 0..a.len() {
        for j in 0..b.len() {
            loop {
                print!("c[{}][{}] = ", i + 1, j + 1);
                try!(io::stdout().flush());
                buffer.clear();
                try!(io::stdin().read_line(&mut buffer));
                match buffer.trim().parse() {
                    Ok(cost) => {
                        c[i][j] = cost;
                        break;
                    }
                    Err(_) => println!("Ошибка: стоимость должна быть целым неотрицательным числом"),
                }
            }
        }
    }

    Ok((a, b, c))
}

fn print_usage(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>...",
                         reason,
                         env::args_os().next().unwrap().to_string_lossy());
    println!("{}", opts.usage(&reason));
}

fn main() {
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(f) => {
            print_usage(&opts, &f.to_string());
            std::process::exit(1);
        }
    };

    if matches.opt_present("h") {
        print_usage(&opts, "");
        std::process::exit(0);
    }

    if matches.free.is_empty() {
        let (a, b, c) = match console_input() {
            Ok((a, b, c)) => (a, b, c),
            Err(err) => panic!(err.to_string()),
        };
        match Transportation::new(a, b, c) {
            Ok(mut t) => {
                t.potential_method();
                t.printstd();
            }
            Err(err) => panic!(err.to_string()),
        };
    } else {
        for file in matches.free.iter().map(PathBuf::from) {
            let (a, b, c) = match file_input(&file) {
                Ok((a, b, c)) => (a, b, c),
                Err(e) => {
                    match e {
                        InputError::Io(err) => panic!(err.to_string()),
                        InputError::Parse(err) => panic!(err.to_string()),
                    }
                }
            };
            match Transportation::new(a, b, c) {
                Ok(mut t) => {
                    println!("{:?}", file);
                    t.potential_method();
                    t.printstd();
                }
                Err(err) => println!("{:?}:{}", file, err.to_string()),
            };
        }
    }
}
<commit_msg>change InputError to Box<Error><commit_after>extern crate getopts;
extern crate transproblem;

use getopts::Options;
use transproblem::Transportation;
use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Write};
use std::path::PathBuf;

fn file_input(file: &PathBuf) -> Result<(Vec<u64>, Vec<u64>, Vec<Vec<u64>>), Box<std::error::Error>> {
    let mut f = BufReader::new(try!(File::open(file)));

    let mut a = String::new();
    try!(f.read_line(&mut a));
    let a: Vec<u64> = try!(a.split_whitespace()
                            .map(|number| number.parse())
                            .collect());

    let mut b = String::new();
    try!(f.read_line(&mut b));
    let b: Vec<u64> = try!(b.split_whitespace()
                            .map(|number| number.parse())
                            .collect());

    let lines: Vec<String> = try!(f.lines().collect());
    let c: Vec<Vec<u64>> = try!(lines.iter()
                                     .filter(|line| !line.is_empty())
                                     .map(|line| {
                                         line.split_whitespace()
                                             .map(|number| number.parse())
                                             .collect()
                                     })
                                     .collect());

    Ok((a, b, c))
}

fn console_input() -> Result<(Vec<u64>, Vec<u64>, Vec<Vec<u64>>), io::Error> {
    let mut a: Vec<u64>;
    let mut b: Vec<u64>;
    let mut c: Vec<Vec<u64>>;
    let mut buffer = String::new();

    println!("Введите количество поставщиков");
    loop {
        print!("A = ");
        try!(io::stdout().flush());
        buffer.clear();
        try!(io::stdin().read_line(&mut buffer));
        match buffer.trim().parse() {
            Ok(size) => {
                a = vec![0;size];
                break;
            }
            Err(_) => println!("Ошибка: количество поставщиков должно быть целым неотрицательным числом"),
        }
    }

    println!("Введите количество потребителей");
    loop {
        print!("B = ");
        try!(io::stdout().flush());
        buffer.clear();
        try!(io::stdin().read_line(&mut buffer));
        match buffer.trim().parse() {
            Ok(size) => {
                b = vec![0;size];
                break;
            }
            Err(_) => println!("Ошибка: количество потребителей должно быть целым неотрицательным числом"),
        }
    }

    println!("Введите количество груза у каждого поставщика");
    for i in 0..a.len() {
        loop {
            print!("a[{}] = ", i + 1);
            try!(io::stdout().flush());
            buffer.clear();
            try!(io::stdin().read_line(&mut buffer));
            match buffer.trim().parse() {
                Ok(amount) => {
                    a[i] = amount;
                    break;
                }
                Err(_) => println!("Ошибка: количество груза должно быть целым неотрицательным числом"),
            }
        }
    }

    println!("Введите количество заказоного груза у каждого потребителя");
    for i in 0..b.len() {
        loop {
            print!("b[{}] = ", i + 1);
            try!(io::stdout().flush());
            buffer.clear();
            try!(io::stdin().read_line(&mut buffer));
            match buffer.trim().parse() {
                Ok(amount) => {
                    b[i] = amount;
                    break;
                }
                Err(_) => println!("Ошибка: количество груза должно быть целым неотрицательным числом"),
            }
        }
    }

    println!("Введите стоимости перевозок");
    c = vec![vec![0;b.len()];a.len()];
    for i in 0..a.len() {
        for j in 0..b.len() {
            loop {
                print!("c[{}][{}] = ", i + 1, j + 1);
                try!(io::stdout().flush());
                buffer.clear();
                try!(io::stdin().read_line(&mut buffer));
                match buffer.trim().parse() {
                    Ok(cost) => {
                        c[i][j] = cost;
                        break;
                    }
                    Err(_) => println!("Ошибка: стоимость должна быть целым неотрицательным числом"),
                }
            }
        }
    }

    Ok((a, b, c))
}

fn print_usage(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>...",
                         reason,
                         env::args_os().next().unwrap().to_string_lossy());
    println!("{}", opts.usage(&reason));
}

fn main() {
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(env::args().skip(1)) {
        Ok(m) => m,
        Err(f) => {
            print_usage(&opts, &f.to_string());
            std::process::exit(1);
        }
    };

    if matches.opt_present("h") {
        print_usage(&opts, "");
        std::process::exit(0);
    }

    if matches.free.is_empty() {
        let (a, b, c) = match console_input() {
            Ok((a, b, c)) => (a, b, c),
            Err(err) => panic!(err.to_string()),
        };
        match Transportation::new(a, b, c) {
            Ok(mut t) => {
                t.potential_method();
                t.printstd();
            }
            Err(err) => panic!(err.to_string()),
        };
    } else {
        for file in matches.free.iter().map(PathBuf::from) {
            let (a, b, c) = match file_input(&file) {
                Ok((a, b, c)) => (a, b, c),
                Err(err) => panic!(err.to_string()),
            };
            match Transportation::new(a, b, c) {
                Ok(mut t) => {
                    println!("{:?}", file);
                    t.potential_method();
                    t.printstd();
                }
                Err(err) => println!("{:?}:{}", file, err.to_string()),
            };
        }
    }
}
<|endoftext|>