<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::{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;
use core_graphics::base::CGFloat;

use libc::c_void;
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::<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)]
pub struct __CTFontDescriptor(c_void);

pub type CTFontDescriptorRef = *const __CTFontDescriptor;

declare_TCFType! {
    CTFontDescriptor, CTFontDescriptorRef
}
impl_TCFType!(CTFontDescriptor, CTFontDescriptorRef, CTFontDescriptorGetTypeID);
impl_CFTypeDescription!(CTFontDescriptor);

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

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<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 {
        unsafe {
            let value = self.get_string_attribute(kCTFontFamilyNameAttribute);
            value.expect("A font must have a non-null family name.")
        }
    }

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

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

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

    pub fn font_path(&self) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.0, kCTFontURLAttribute);
            if value.is_null() {
                return None;
            }

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(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>Properly release attribute returned by CTFontDescriptorCopyAttribute<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::{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;
use core_graphics::base::CGFloat;

use libc::c_void;
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::<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)]
pub struct __CTFontDescriptor(c_void);

pub type CTFontDescriptorRef = *const __CTFontDescriptor;

declare_TCFType! {
    CTFontDescriptor, CTFontDescriptorRef
}
impl_TCFType!(CTFontDescriptor, CTFontDescriptorRef, CTFontDescriptorGetTypeID);
impl_CFTypeDescription!(CTFontDescriptor);

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

            let value: CFType = TCFType::wrap_under_create_rule(value);
            assert!(value.instance_of::<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 {
        unsafe {
            let value = self.get_string_attribute(kCTFontFamilyNameAttribute);
            value.expect("A font must have a non-null family name.")
        }
    }

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

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

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

    pub fn font_path(&self) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.0, kCTFontURLAttribute);
            if value.is_null() {
                return None;
            }

            let value: CFType = TCFType::wrap_under_create_rule(value);
            assert!(value.instance_of::<CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(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>use std::marker::PhantomData;

use crate::context::{Has, HasMut};

use super::{
    context::GraphicsContext,
    gpu::{
        arc::{ArcBindGroup, ArcBindGroupLayout, ArcBuffer, ArcShaderModule},
        bind_group::BindGroupBuilder,
    },
    image::Image,
    sampler::Sampler,
};
use crevice::std140::Std140;
use wgpu::util::DeviceExt;

/// A custom fragment shader that can be used to render with shader effects.
///
/// Adapted from the `shader.rs` example:
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// #[derive(AsStd140)]
/// struct Dim {
///     rate: f32,
/// }
///
/// struct MainState {}
///
/// impl event::EventHandler for MainState {
/// #   fn update(&mut self, _ctx: &mut Context) -> Result<(), GameError> { Ok(()) }
///     fn draw(&mut self, ctx: &mut Context) -> GameResult {
///         let mut canvas = graphics::Canvas::from_frame(ctx, Color::BLACK);
///         let dim = Dim { rate: 0.5 };
///         // NOTE: This is for simplicity; do not recreate your shader every frame like this!
///         //       For more info look at the full example.
///         let shader = Shader::from_wgsl(
///             ctx,
///             include_str!("../../resources/dimmer.wgsl"),
///             "main"
///         );
///         let params = ShaderParams::new(ctx, &dim, &[], &[]);
///         params.set_uniforms(ctx, &dim);
///
///         canvas.set_shader(shader);
///         canvas.set_shader_params(params);
///         // draw something...
///         canvas.finish(ctx)
///     }
///
///     /* ... */
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Shader {
    pub(crate) fragment: ArcShaderModule,
    pub(crate) fs_entry: String,
}

impl Shader {
    /// Creates a shader from a WGSL string.
    pub fn from_wgsl(gfx: &impl Has<GraphicsContext>, wgsl: &str, fs_entry: &str) -> Self {
        let gfx = gfx.retrieve();
        let module = ArcShaderModule::new(gfx.wgpu.device.create_shader_module(
            &wgpu::ShaderModuleDescriptor {
                label: None,
                source: wgpu::ShaderSource::Wgsl(wgsl.into()),
            },
        ));

        Shader {
            fragment: module,
            fs_entry: fs_entry.into(),
        }
    }
}

pub use crevice::std140::AsStd140;

/// Parameters that can be passed to a custom shader, including uniforms, images, and samplers.
#[allow(clippy::derive_partial_eq_without_eq)] // False positive?
#[derive(Debug, PartialEq, Eq)]
pub struct ShaderParams<Uniforms: AsStd140> {
    pub(crate) uniforms: ArcBuffer,
    pub(crate) layout: ArcBindGroupLayout,
    pub(crate) bind_group: ArcBindGroup,
    _marker: PhantomData<Uniforms>,
}

impl<Uniforms: AsStd140> ShaderParams<Uniforms> {
    /// Creates a new [ShaderParams], initialized with the given uniforms, images, and samplers.
    pub fn new(
        gfx: &mut impl HasMut<GraphicsContext>,
        uniforms: &Uniforms,
        images: &[&Image],
        samplers: &[Sampler],
    ) -> Self {
        let gfx = gfx.retrieve_mut();
        let uniforms = ArcBuffer::new(gfx.wgpu.device.create_buffer_init(
            &wgpu::util::BufferInitDescriptor {
                label: None,
                usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
                contents: uniforms.as_std140().as_bytes(),
            },
        ));

        let samplers = samplers
            .iter()
            .map(|&sampler| gfx.sampler_cache.get(&gfx.wgpu.device, sampler))
            .collect::<Vec<_>>();

        let mut builder = BindGroupBuilder::new();
        builder = builder.buffer(
            &uniforms,
            0,
            wgpu::ShaderStages::VERTEX_FRAGMENT,
            wgpu::BufferBindingType::Uniform,
            false,
            None,
        );

        for image in images {
            builder = builder.image(&image.view, wgpu::ShaderStages::FRAGMENT);
        }

        for sampler in &samplers {
            builder = builder.sampler(sampler, wgpu::ShaderStages::FRAGMENT);
        }

        let (bind_group, layout) = builder.create(&gfx.wgpu.device, &mut gfx.bind_group_cache);

        ShaderParams {
            uniforms,
            layout,
            bind_group,
            _marker: PhantomData,
        }
    }

    /// Updates the uniform data.
    pub fn set_uniforms(&self, gfx: &impl Has<GraphicsContext>, uniforms: &Uniforms) {
        let gfx = gfx.retrieve();
        gfx.wgpu
            .queue
            .write_buffer(&self.uniforms, 0, uniforms.as_std140().as_bytes());
    }
}

impl<Uniforms: AsStd140> Clone for ShaderParams<Uniforms> {
    fn clone(&self) -> Self {
        Self {
            uniforms: self.uniforms.clone(),
            layout: self.layout.clone(),
            bind_group: self.bind_group.clone(),
            _marker: PhantomData,
        }
    }
}

pub use wgpu::{BlendComponent, BlendFactor, BlendOperation};

/// Describes the blend mode used when drawing images.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BlendMode {
    /// The blend mode for the color channels.
    pub color: BlendComponent,
    /// The blend mode for the alpha channel.
    pub alpha: BlendComponent,
}

impl BlendMode {
    /// When combining two fragments, add their values together, saturating
    /// at 1.0
    pub const ADD: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, subtract the source value from the
    /// destination value
    pub const SUBTRACT: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::ReverseSubtract,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::Zero,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, add the value of the source times its
    /// alpha channel with the value of the destination multiplied by the inverse
    /// of the source alpha channel. Has the usual transparency effect: mixes the
    /// two colors using a fraction of each one specified by the alpha of the source.
    pub const ALPHA: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::OneMinusSrcAlpha,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, subtract the destination color from a constant
    /// color using the source color as weight. Has an invert effect with the constant
    /// color as base and source color controlling displacement from the base color.
    /// A white source color and a white value results in plain invert. The output
    /// alpha is same as destination alpha.
    pub const INVERT: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::Constant,
            dst_factor: BlendFactor::Src,
            operation: BlendOperation::Subtract,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::Zero,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, multiply their values together (including alpha)
    pub const MULTIPLY: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::Dst,
            dst_factor: BlendFactor::Zero,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::DstAlpha,
            dst_factor: BlendFactor::Zero,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, choose the source value (including source alpha)
    pub const REPLACE: Self = BlendMode {
        color: wgpu::BlendState::REPLACE.color,
        alpha: wgpu::BlendState::REPLACE.alpha,
    };

    /// When combining two fragments, choose the lighter value
    pub const LIGHTEN: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Max,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, choose the darker value
    pub const DARKEN: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Min,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When using premultiplied alpha, use this.
    ///
    /// You usually want to use this blend mode for drawing canvases
    /// containing semi-transparent imagery.
    /// For an explanation on this see: <https://github.com/ggez/ggez/issues/694#issuecomment-853724926>
    pub const PREMULTIPLIED: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::One,
            dst_factor: BlendFactor::OneMinusSrcAlpha,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };
}
<commit_msg>Removes allow since it's a nightly lint<commit_after>use std::marker::PhantomData;

use crate::context::{Has, HasMut};

use super::{
    context::GraphicsContext,
    gpu::{
        arc::{ArcBindGroup, ArcBindGroupLayout, ArcBuffer, ArcShaderModule},
        bind_group::BindGroupBuilder,
    },
    image::Image,
    sampler::Sampler,
};
use crevice::std140::Std140;
use wgpu::util::DeviceExt;

/// A custom fragment shader that can be used to render with shader effects.
///
/// Adapted from the `shader.rs` example:
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// #[derive(AsStd140)]
/// struct Dim {
///     rate: f32,
/// }
///
/// struct MainState {}
///
/// impl event::EventHandler for MainState {
/// #   fn update(&mut self, _ctx: &mut Context) -> Result<(), GameError> { Ok(()) }
///     fn draw(&mut self, ctx: &mut Context) -> GameResult {
///         let mut canvas = graphics::Canvas::from_frame(ctx, Color::BLACK);
///         let dim = Dim { rate: 0.5 };
///         // NOTE: This is for simplicity; do not recreate your shader every frame like this!
///         //       For more info look at the full example.
///         let shader = Shader::from_wgsl(
///             ctx,
///             include_str!("../../resources/dimmer.wgsl"),
///             "main"
///         );
///         let params = ShaderParams::new(ctx, &dim, &[], &[]);
///         params.set_uniforms(ctx, &dim);
///
///         canvas.set_shader(shader);
///         canvas.set_shader_params(params);
///         // draw something...
///         canvas.finish(ctx)
///     }
///
///     /* ... */
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Shader {
    pub(crate) fragment: ArcShaderModule,
    pub(crate) fs_entry: String,
}

impl Shader {
    /// Creates a shader from a WGSL string.
    pub fn from_wgsl(gfx: &impl Has<GraphicsContext>, wgsl: &str, fs_entry: &str) -> Self {
        let gfx = gfx.retrieve();
        let module = ArcShaderModule::new(gfx.wgpu.device.create_shader_module(
            &wgpu::ShaderModuleDescriptor {
                label: None,
                source: wgpu::ShaderSource::Wgsl(wgsl.into()),
            },
        ));

        Shader {
            fragment: module,
            fs_entry: fs_entry.into(),
        }
    }
}

pub use crevice::std140::AsStd140;

/// Parameters that can be passed to a custom shader, including uniforms, images, and samplers.
#[derive(Debug, PartialEq, Eq)]
pub struct ShaderParams<Uniforms: AsStd140> {
    pub(crate) uniforms: ArcBuffer,
    pub(crate) layout: ArcBindGroupLayout,
    pub(crate) bind_group: ArcBindGroup,
    _marker: PhantomData<Uniforms>,
}

impl<Uniforms: AsStd140> ShaderParams<Uniforms> {
    /// Creates a new [ShaderParams], initialized with the given uniforms, images, and samplers.
    pub fn new(
        gfx: &mut impl HasMut<GraphicsContext>,
        uniforms: &Uniforms,
        images: &[&Image],
        samplers: &[Sampler],
    ) -> Self {
        let gfx = gfx.retrieve_mut();
        let uniforms = ArcBuffer::new(gfx.wgpu.device.create_buffer_init(
            &wgpu::util::BufferInitDescriptor {
                label: None,
                usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
                contents: uniforms.as_std140().as_bytes(),
            },
        ));

        let samplers = samplers
            .iter()
            .map(|&sampler| gfx.sampler_cache.get(&gfx.wgpu.device, sampler))
            .collect::<Vec<_>>();

        let mut builder = BindGroupBuilder::new();
        builder = builder.buffer(
            &uniforms,
            0,
            wgpu::ShaderStages::VERTEX_FRAGMENT,
            wgpu::BufferBindingType::Uniform,
            false,
            None,
        );

        for image in images {
            builder = builder.image(&image.view, wgpu::ShaderStages::FRAGMENT);
        }

        for sampler in &samplers {
            builder = builder.sampler(sampler, wgpu::ShaderStages::FRAGMENT);
        }

        let (bind_group, layout) = builder.create(&gfx.wgpu.device, &mut gfx.bind_group_cache);

        ShaderParams {
            uniforms,
            layout,
            bind_group,
            _marker: PhantomData,
        }
    }

    /// Updates the uniform data.
    pub fn set_uniforms(&self, gfx: &impl Has<GraphicsContext>, uniforms: &Uniforms) {
        let gfx = gfx.retrieve();
        gfx.wgpu
            .queue
            .write_buffer(&self.uniforms, 0, uniforms.as_std140().as_bytes());
    }
}

impl<Uniforms: AsStd140> Clone for ShaderParams<Uniforms> {
    fn clone(&self) -> Self {
        Self {
            uniforms: self.uniforms.clone(),
            layout: self.layout.clone(),
            bind_group: self.bind_group.clone(),
            _marker: PhantomData,
        }
    }
}

pub use wgpu::{BlendComponent, BlendFactor, BlendOperation};

/// Describes the blend mode used when drawing images.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BlendMode {
    /// The blend mode for the color channels.
    pub color: BlendComponent,
    /// The blend mode for the alpha channel.
    pub alpha: BlendComponent,
}

impl BlendMode {
    /// When combining two fragments, add their values together, saturating
    /// at 1.0
    pub const ADD: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, subtract the source value from the
    /// destination value
    pub const SUBTRACT: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::ReverseSubtract,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::Zero,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, add the value of the source times its
    /// alpha channel with the value of the destination multiplied by the inverse
    /// of the source alpha channel. Has the usual transparency effect: mixes the
    /// two colors using a fraction of each one specified by the alpha of the source.
    pub const ALPHA: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::OneMinusSrcAlpha,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, subtract the destination color from a constant
    /// color using the source color as weight. Has an invert effect with the constant
    /// color as base and source color controlling displacement from the base color.
    /// A white source color and a white value results in plain invert. The output
    /// alpha is same as destination alpha.
    pub const INVERT: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::Constant,
            dst_factor: BlendFactor::Src,
            operation: BlendOperation::Subtract,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::Zero,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, multiply their values together (including alpha)
    pub const MULTIPLY: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::Dst,
            dst_factor: BlendFactor::Zero,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::DstAlpha,
            dst_factor: BlendFactor::Zero,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, choose the source value (including source alpha)
    pub const REPLACE: Self = BlendMode {
        color: wgpu::BlendState::REPLACE.color,
        alpha: wgpu::BlendState::REPLACE.alpha,
    };

    /// When combining two fragments, choose the lighter value
    pub const LIGHTEN: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Max,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When combining two fragments, choose the darker value
    pub const DARKEN: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::SrcAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Min,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };

    /// When using premultiplied alpha, use this.
    ///
    /// You usually want to use this blend mode for drawing canvases
    /// containing semi-transparent imagery.
    /// For an explanation on this see: <https://github.com/ggez/ggez/issues/694#issuecomment-853724926>
    pub const PREMULTIPLIED: Self = BlendMode {
        color: BlendComponent {
            src_factor: BlendFactor::One,
            dst_factor: BlendFactor::OneMinusSrcAlpha,
            operation: BlendOperation::Add,
        },
        alpha: BlendComponent {
            src_factor: BlendFactor::OneMinusDstAlpha,
            dst_factor: BlendFactor::One,
            operation: BlendOperation::Add,
        },
    };
}
<|endoftext|>


<commit_before>//! 2D grid with neighbors iter and custom internal coordinate.

mod iter;
mod coord;
mod test;

use std::mem;

use scoped_threadpool::Pool;

use traits::Grid;
use traits::Cell;
use traits::EvolutionState;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

/// 2D grid. Implemented with two buffers.
/// They are swapped on every evolution step.
/// Old buffer is used for read-only neighbors data.
/// New buffer is writable and mutated through update process.
/// Grid uses one-dimensional `Vec` to store cells.
pub struct TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    cells: Vec<C>,
    old_cells: Vec<C>,
    evolution_state: C::State,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: i32,
    cols: i32,
    pool: Option<Pool>,
    separate: bool,
}

impl<C, N> TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    /// Constructs TwodimGrid with given ROWSxCOLS, neighborhood
    /// strategy, initial evolution state and threads count.
    pub fn new(rows: i32,
               cols: i32,
               nhood: N,
               state: C::State,
               threads: u32,
               separate: bool)
               -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let threads = if separate {
            threads
        } else {
            threads - 1
        };
        let pool = if threads > 1 {
            Some(Pool::new(threads))
        } else {
            None
        };

        let mut grid = TwodimGrid {
            cells: cells,
            old_cells: old_cells,
            evolution_state: state,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols, rows),
            pool: pool,
            separate: separate,
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        for offset in 0..self.rows * self.cols {

            let coord = GridCoord::from_offset(offset as i32, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            let cell = C::with_coord(coord);
            self.cells.push(cell.clone());
            self.old_cells.push(cell.clone());
        }
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        for coord in self.nhood.neighbors(coord).iter() {

            if coord.x() >= 0 && coord.x() < self.cols && coord.y() >= 0 && coord.y() < self.rows {
                neighbors.push(Some(self.offset(coord)));
            } else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    fn neighbors_iter<'b>(&self,
                          cells: &'b Vec<C>,
                          neighbors: &'b Vec<Option<usize>>)
                          -> Iter<'b, C> {

        Iter::new(cells, neighbors, self.nhood.neighbors_count())
    }

    #[inline]
    fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols + coord.x()) as usize
    }
}

impl<C, N> Grid for TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    type Cell = C;
    type Coord = GridCoord;

    fn update(&mut self) {
        mem::swap(&mut self.cells, &mut self.old_cells);

        for i in 0..self.cells.len() {
            unsafe {
                let ref neighbors = self.neighbors.get_unchecked(i);
                let neighbors_iter = self.neighbors_iter(&self.old_cells, &neighbors);

                let old = self.old_cells.get_unchecked(i);
                let cell = self.cells.get_unchecked_mut(i);
                cell.update(old, neighbors_iter, &self.evolution_state);
            }
        }

        self.evolution_state.update();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> { &self.cells }

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State { &self.evolution_state }

    fn dimensions(&self) -> Self::Coord { self.dimensions.clone() }
}
<commit_msg>Some documentation.<commit_after>//! 2D grid with neighbors iter and custom internal coordinate.

mod iter;
mod coord;
mod test;

use std::mem;

use scoped_threadpool::Pool;

use traits::Grid;
use traits::Cell;
use traits::EvolutionState;
use traits::Nhood;
use traits::Coord;

use self::iter::Iter;
pub use self::coord::GridCoord;

/// 2D grid. Implemented with two buffers.
/// They are swapped on every evolution step.
/// Old buffer is used for read-only neighbors data.
/// New buffer is writable and mutated through update process.
/// Grid uses one-dimensional `Vec` to store cells.
pub struct TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    cells: Vec<C>,
    old_cells: Vec<C>,
    evolution_state: C::State,
    nhood: N,
    neighbors: Vec<Vec<Option<usize>>>,
    dimensions: GridCoord,
    rows: i32,
    cols: i32,
    pool: Option<Pool>,
    separate: bool,
}

impl<C, N> TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    /// Constructs TwodimGrid with given ROWSxCOLS, neighborhood
    /// strategy, initial evolution state, threads count and separate flag.
    ///
    /// Separate flag means grid will not use thread it's called from.
    pub fn new(rows: i32,
               cols: i32,
               nhood: N,
               state: C::State,
               threads: u32,
               separate: bool)
               -> Self {

        let len = (rows * cols) as usize;

        let cells = Vec::with_capacity(len);
        let old_cells = Vec::with_capacity(len);
        let neighbors = Vec::with_capacity(len);

        let threads = if separate {
            threads
        } else {
            threads - 1
        };
        let pool = if threads > 1 {
            Some(Pool::new(threads))
        } else {
            None
        };

        let mut grid = TwodimGrid {
            cells: cells,
            old_cells: old_cells,
            evolution_state: state,
            nhood: nhood,
            neighbors: neighbors,
            rows: rows,
            cols: cols,
            dimensions: GridCoord::from_2d(cols, rows),
            pool: pool,
            separate: separate,
        };

        grid.init();

        grid
    }

    fn init(&mut self) {

        for offset in 0..self.rows * self.cols {

            let coord = GridCoord::from_offset(offset as i32, self.rows, self.cols);

            // init neighbors
            let neighbors = self.get_neighbors(&coord);
            self.neighbors.push(neighbors);

            // init cells
            let cell = C::with_coord(coord);
            self.cells.push(cell.clone());
            self.old_cells.push(cell.clone());
        }
    }

    fn get_neighbors(&self, coord: &GridCoord) -> Vec<Option<usize>> {

        let neighbors_count = self.nhood.neighbors_count();
        let mut neighbors = Vec::with_capacity(neighbors_count);

        for coord in self.nhood.neighbors(coord).iter() {

            if coord.x() >= 0 && coord.x() < self.cols && coord.y() >= 0 && coord.y() < self.rows {
                neighbors.push(Some(self.offset(coord)));
            } else {
                neighbors.push(None);
            }
        }

        neighbors
    }

    fn neighbors_iter<'b>(&self,
                          cells: &'b Vec<C>,
                          neighbors: &'b Vec<Option<usize>>)
                          -> Iter<'b, C> {

        Iter::new(cells, neighbors, self.nhood.neighbors_count())
    }

    #[inline]
    fn offset<Crd: Coord>(&self, coord: &Crd) -> usize {
        (coord.y() * self.cols + coord.x()) as usize
    }
}

impl<C, N> Grid for TwodimGrid<C, N>
    where C: Cell + Clone,
          N: Nhood<Coord = GridCoord>,
{
    type Cell = C;
    type Coord = GridCoord;

    fn update(&mut self) {
        mem::swap(&mut self.cells, &mut self.old_cells);

        for i in 0..self.cells.len() {
            unsafe {
                let ref neighbors = self.neighbors.get_unchecked(i);
                let neighbors_iter = self.neighbors_iter(&self.old_cells, &neighbors);

                let old = self.old_cells.get_unchecked(i);
                let cell = self.cells.get_unchecked_mut(i);
                cell.update(old, neighbors_iter, &self.evolution_state);
            }
        }

        self.evolution_state.update();
    }

    fn set_cells(&mut self, new_cells: Vec<Self::Cell>) {

        for cell in new_cells.into_iter() {

            let index;

            {
                index = self.offset(cell.coord());
            }

            self.cells[index] = cell;
        }
    }

    fn cells(&self) -> &Vec<Self::Cell> { &self.cells }

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State { &self.evolution_state }

    fn dimensions(&self) -> Self::Coord { self.dimensions.clone() }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! HAL for NXP LPC17xx.

pub mod system_clock;
pub mod peripheral_clock;
pub mod pin;
pub mod pwm;
// pub mod ssp;
pub mod timer;
pub mod uart;
<commit_msg>clocks and timers and pwm are uart is for chumps<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! HAL for NXP LPC17xx.

pub mod system_clock;
pub mod pin;
// pub mod ssp;
<|endoftext|>


<commit_before>use iron::prelude::*;
use iron::status;
use iron::mime::Mime;

use rustc_serialize::json;

use engine::{SemanticEngine, Completion, Context, CursorPosition, Buffer};
use super::EngineProvider;

/// Given a location, return a list of possible completions
pub fn list(req: &mut Request) -> IronResult<Response> {
    let lcr = match req.get::<::bodyparser::Struct<ListCompletionsRequest>>() {
        Ok(Some(s)) => {
            trace!("parsed ListCompletionsRequest");
            s
        },
        Ok(None) => {
            trace!("failed parsing ListCompletionsRequest");
            return Ok(Response::with(status::BadRequest))
        },
        Err(err) => {
            trace!("error while parsing ListCompletionsRequest");
            return Err(IronError::new(err, status::InternalServerError))
        }
    };

    let mutex = req.get::<::persistent::Write<EngineProvider>>().unwrap();
    let engine = mutex.lock().unwrap();
    match engine.list_completions(&lcr.context()) {
        // 200 OK; found the definition
        Ok(Some(completions)) => {
            trace!("got a match");
            let res = completions.into_iter().map(|c| CompletionResponse::from(c)).collect::<Vec<_>>();
            let content_type = "application/json".parse::<Mime>().unwrap();
            Ok(Response::with((content_type, status::Ok, json::encode(&res).unwrap())))
        },

        // 204 No Content; Everything went ok, but the definition was not found.
        Ok(None) => {
            trace!("did not find any match");
            Ok(Response::with(status::NoContent))
        },

        // 500 Internal Server Error; Error occurred while searching for the definition
        Err(err) => {
            trace!("encountered an error");
            Err(IronError::new(err, status::InternalServerError))
        }
    }
}

#[derive(Debug, RustcDecodable, Clone)]
struct ListCompletionsRequest {
    pub buffers: Vec<Buffer>,
    pub file_path: String,
    pub column: usize,
    pub line: usize,
}

impl ListCompletionsRequest {
    pub fn context(self) -> Context {
        let cursor = CursorPosition { line: self.line, col: self.column };
        Context::new(self.buffers, cursor, self.file_path)
    }
}

type ListCompletionsResponse = Vec<CompletionResponse>;

#[derive(Debug, RustcEncodable)]
struct CompletionResponse {
    text: String,
    context: String,
    kind: String,
    file_path: String,
    line: usize,
    column: usize
}

impl From<Completion> for CompletionResponse {
    fn from(c: Completion) -> CompletionResponse {
         CompletionResponse {
            text: c.text,
            context: c.context,
            kind: c.kind,
            file_path: c.file_path,
            line: c.position.line,
            column: c.position.col
         }
    }
}

<commit_msg>Avoid lock poisoning<commit_after>use iron::prelude::*;
use iron::status;
use iron::mime::Mime;

use rustc_serialize::json;

use engine::{SemanticEngine, Completion, Context, CursorPosition, Buffer};
use super::EngineProvider;

/// Given a location, return a list of possible completions
pub fn list(req: &mut Request) -> IronResult<Response> {
    let lcr = match req.get::<::bodyparser::Struct<ListCompletionsRequest>>() {
        Ok(Some(s)) => {
            trace!("parsed ListCompletionsRequest");
            s
        },
        Ok(None) => {
            trace!("failed parsing ListCompletionsRequest");
            return Ok(Response::with(status::BadRequest))
        },
        Err(err) => {
            trace!("error while parsing ListCompletionsRequest");
            return Err(IronError::new(err, status::InternalServerError))
        }
    };

    let mutex = req.get::<::persistent::Write<EngineProvider>>().unwrap();
    let engine = mutex.lock().unwrap_or_else(|e| e.into_inner());
    match engine.list_completions(&lcr.context()) {
        // 200 OK; found the definition
        Ok(Some(completions)) => {
            trace!("got a match");
            let res = completions.into_iter().map(|c| CompletionResponse::from(c)).collect::<Vec<_>>();
            let content_type = "application/json".parse::<Mime>().unwrap();
            Ok(Response::with((content_type, status::Ok, json::encode(&res).unwrap())))
        },

        // 204 No Content; Everything went ok, but the definition was not found.
        Ok(None) => {
            trace!("did not find any match");
            Ok(Response::with(status::NoContent))
        },

        // 500 Internal Server Error; Error occurred while searching for the definition
        Err(err) => {
            trace!("encountered an error");
            Err(IronError::new(err, status::InternalServerError))
        }
    }
}

#[derive(Debug, RustcDecodable, Clone)]
struct ListCompletionsRequest {
    pub buffers: Vec<Buffer>,
    pub file_path: String,
    pub column: usize,
    pub line: usize,
}

impl ListCompletionsRequest {
    pub fn context(self) -> Context {
        let cursor = CursorPosition { line: self.line, col: self.column };
        Context::new(self.buffers, cursor, self.file_path)
    }
}

type ListCompletionsResponse = Vec<CompletionResponse>;

#[derive(Debug, RustcEncodable)]
struct CompletionResponse {
    text: String,
    context: String,
    kind: String,
    file_path: String,
    line: usize,
    column: usize
}

impl From<Completion> for CompletionResponse {
    fn from(c: Completion) -> CompletionResponse {
         CompletionResponse {
            text: c.text,
            context: c.context,
            kind: c.kind,
            file_path: c.file_path,
            line: c.position.line,
            column: c.position.col
         }
    }
}

<|endoftext|>


<commit_before>/// If the next token matches `$p`, consume that token and execute `$eval`.
#[macro_export]
macro_rules! allow {
    ($parser:ident, $p:pat => $eval:expr) => {
        match $parser.lexer.token {
            $p => {
                $parser.lexer.consume();
                $eval;
            },
            _ => {}
        }
    }
}

/// Return an error if the next token doesn't match $p.
#[macro_export]
macro_rules! expect {
    ($parser:ident, $p:pat) => {
        match $parser.lexer.token {
            $p => $parser.lexer.consume(),
            _  => $parser.error()
        }
    }
}

#[macro_export]
macro_rules! parameter_key {
    ($parser:ident) => {
        match $parser.lexer.token {
            ParenClose        => {
                $parser.lexer.consume();
                break;
            },
            Identifier => {
                let ident = $parser.lexer.token_as_str();
                $parser.lexer.consume();
                ParameterKey::Identifier(ident)
            },
            _ => return $parser.error()
        }
    }
}

#[cfg(test)]
#[macro_export]
macro_rules! assert_expr {
    ($src:expr, $expr:expr) => ({
        let mut body = parse($src).unwrap().body().iter();

        match body.next().map(|s| s.item).unwrap() {
            Statement::Expression(ref expression) => assert_eq!(expression.item, Expression::from($expr)),
            _ => panic!("Statement isn't an expression!")
        }

        assert_eq!(body.next(), None);
    })
}
<commit_msg>Hotfix for unsoundness in tests<commit_after>/// If the next token matches `$p`, consume that token and execute `$eval`.
#[macro_export]
macro_rules! allow {
    ($parser:ident, $p:pat => $eval:expr) => {
        match $parser.lexer.token {
            $p => {
                $parser.lexer.consume();
                $eval;
            },
            _ => {}
        }
    }
}

/// Return an error if the next token doesn't match $p.
#[macro_export]
macro_rules! expect {
    ($parser:ident, $p:pat) => {
        match $parser.lexer.token {
            $p => $parser.lexer.consume(),
            _  => $parser.error()
        }
    }
}

#[macro_export]
macro_rules! parameter_key {
    ($parser:ident) => {
        match $parser.lexer.token {
            ParenClose        => {
                $parser.lexer.consume();
                break;
            },
            Identifier => {
                let ident = $parser.lexer.token_as_str();
                $parser.lexer.consume();
                ParameterKey::Identifier(ident)
            },
            _ => return $parser.error()
        }
    }
}

#[cfg(test)]
#[macro_export]
macro_rules! assert_expr {
    ($src:expr, $expr:expr) => ({
        let module = parse($src).unwrap();
        let mut body = module.body().iter();

        match body.next().map(|s| s.item).unwrap() {
            Statement::Expression(ref expression) => assert_eq!(expression.item, Expression::from($expr)),
            _ => panic!("Statement isn't an expression!")
        }

        assert_eq!(body.next(), None);
    })
}
<|endoftext|>


<commit_before>use std::iter;

// FIXME: only supports extended-ASCII
/// searches for the pattern in the input text using the
/// KMP algorithm.
pub struct KMP<'a> {
    r: usize,
    dfa: Vec<Vec<usize>>,
    pat: &'a str
}

impl<'a> KMP<'a> {
    // create the DFA from a string pattern
    pub fn new<'b>(pat: &'b str) -> KMP<'b> {
        let r = 256;
        let m = pat.len();
        let dfa = iter::repeat(iter::repeat(0).take(m).collect::<Vec<usize>>())
            .take(r).collect();

        let mut ret = KMP {
            r: r,
            dfa: dfa,
            pat: pat
        };
        ret.build_dfa();
        ret
    }

    fn build_dfa(&mut self) {
        let m = self.pat.len();
        let r = self.r;
        self.dfa[self.pat.char_at(0) as usize][0] = 1;
        let mut x = 0;
        for j in 1 .. m {
            for c in 0 .. r {
                self.dfa[c][j] = self.dfa[c][x]; // copy mismatch cases
            }
            self.dfa[self.pat.char_at(j) as usize][j] = j+1; // set match case
            x = self.dfa[self.pat.char_at(j) as usize][x];   // update restart state
        }
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let m = self.pat.len();
        let n = txt.len();
        let mut i = 0;
        let mut j = 0;
        while i < n && j < m {
            j = self.dfa[txt.char_at(i) as usize][j];
            i += 1;
        }
        if j == m {
            Some(i-m)
        } else {
            None
        }
    }
}

#[test]
fn test_kmp() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let kmp = KMP::new(pat);
    assert!(kmp.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(kmp.search("zzzzz"), None);
}

/// searches for the pattern in the input text using the
/// bad-character rule part of the Boyer-Moore algorithm.
pub struct BoyerMoore<'a> {
    r: usize,
    right: Vec<isize>,
    pat: &'a str
}

impl<'a> BoyerMoore<'a> {
     pub fn new<'b>(pat: &'b str) -> BoyerMoore<'b> {
         let r = 256;
         let mut ret = BoyerMoore {
             r: r,
             right: Vec::new(),
             pat: pat
         };
         ret.init();
         ret
     }

    fn init(&mut self) {
        let r = self.r;
        self.right = iter::repeat(-1).take(r).collect();
        for j in 0 .. self.pat.len() {
            self.right[self.pat.char_at(j) as usize] = j as isize;
        }
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let m = self.pat.len();
        let n = txt.len();
        if n < m {
            return None;
        }
        let mut skip;
        let mut i = 0;
        while i <= n-m {
            skip = 0;
            for j in (0 .. m).rev() {
                if self.pat.char_at(j) != txt.char_at(i+j) {
                    skip = j as isize - self.right[txt.char_at(i+j) as usize];
                    if skip < 1 {
                        skip = 1;
                    }
                    break;
                }
            }
            if skip == 0 {
                return Some(i);
            }
            i += skip as usize;
        }
        return None;
    }
}

#[test]
fn test_boyer_moore() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let bm = BoyerMoore::new(pat);
    assert!(bm.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(bm.search("zzzzz"), None);
}
<commit_msg>substring_search: implement RabinKarp for string<commit_after>use std::iter;

// FIXME: only supports extended-ASCII
/// searches for the pattern in the input text using the
/// KMP algorithm.
pub struct KMP<'a> {
    r: usize,
    dfa: Vec<Vec<usize>>,
    pat: &'a str
}

impl<'a> KMP<'a> {
    // create the DFA from a string pattern
    pub fn new<'b>(pat: &'b str) -> KMP<'b> {
        let r = 256;
        let mut ret = KMP {
            r: r,
            dfa: Vec::new(),
            pat: pat
        };
        ret.build_dfa();
        ret
    }

    fn build_dfa(&mut self) {
        let m = self.pat.len();
        let r = self.r;
        let mut dfa = iter::repeat(iter::repeat(0).take(m).collect::<Vec<usize>>())
            .take(r).collect::<Vec<Vec<usize>>>();
        dfa[self.pat.char_at(0) as usize][0] = 1;
        let mut x = 0;
        for j in 1 .. m {
            for c in 0 .. r {
                dfa[c][j] = dfa[c][x]; // copy mismatch cases
            }
            dfa[self.pat.char_at(j) as usize][j] = j+1; // set match case
            x = dfa[self.pat.char_at(j) as usize][x];   // update restart state
        }
        self.dfa = dfa;
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let m = self.pat.len();
        let n = txt.len();
        let mut i = 0;
        let mut j = 0;
        while i < n && j < m {
            j = self.dfa[txt.char_at(i) as usize][j];
            i += 1;
        }
        if j == m {
            Some(i-m)
        } else {
            None
        }
    }
}

#[test]
fn test_kmp() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let kmp = KMP::new(pat);
    assert!(kmp.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(kmp.search("zzzzz"), None);
}

/// searches for the pattern in the input text using the
/// bad-character rule part of the Boyer-Moore algorithm.
pub struct BoyerMoore<'a> {
    r: usize,
    right: Vec<isize>,
    pat: &'a str
}

impl<'a> BoyerMoore<'a> {
     pub fn new<'b>(pat: &'b str) -> BoyerMoore<'b> {
         let r = 256;
         let mut ret = BoyerMoore {
             r: r,
             right: Vec::new(),
             pat: pat
         };
         ret.init();
         ret
     }

    fn init(&mut self) {
        let r = self.r;
        self.right = iter::repeat(-1).take(r).collect();
        for j in 0 .. self.pat.len() {
            self.right[self.pat.char_at(j) as usize] = j as isize;
        }
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let m = self.pat.len();
        let n = txt.len();
        if n < m {
            return None;
        }
        let mut skip;
        let mut i = 0;
        while i <= n-m {
            skip = 0;
            for j in (0 .. m).rev() {
                if self.pat.char_at(j) != txt.char_at(i+j) {
                    skip = j as isize - self.right[txt.char_at(i+j) as usize];
                    if skip < 1 {
                        skip = 1;
                    }
                    break;
                }
            }
            if skip == 0 {
                return Some(i);
            }
            i += skip as usize;
        }
        return None;
    }
}

#[test]
fn test_boyer_moore() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let bm = BoyerMoore::new(pat);
    assert!(bm.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(bm.search("zzzzz"), None);
}

pub struct RabinKarp<'a> {
    pat: &'a str,
    pat_hash: usize,
    m: usize,
    r: usize,
    q: usize,
    rm: usize,                    // R^(M-1) % Q
}

impl<'a> RabinKarp<'a> {
    pub fn new<'b>(pat: &'b str) -> RabinKarp<'b> {
        let mut ret = RabinKarp {
            pat: pat,
            pat_hash: 0,
            m: pat.len(),
            r: 256,
            q: RabinKarp::long_random_prime(),
            rm: 1
        };
        ret.init();
        ret
    }

    fn init(&mut self) {
        let r = self.r;
        let q = self.q;
        for _ in 1 .. self.m {
            self.rm = (r * self.rm) % q;
        }
        self.pat_hash = self.hash(self.pat, self.m);
    }

    fn hash(&self, key: &str, m: usize) -> usize {
        let r = self.r;
        let q = self.q;
        let mut h = 0;
        for j in 0 .. m {
            h = (r * h + key.char_at(j) as usize) % q
        }
        h
    }

    fn check(&self, txt: &str, i: usize) -> bool {
        for j in 0 .. self.m {
            if self.pat.char_at(j) != txt.char_at(i+j) {
                return false;
            }
        }
        true
    }

    pub fn search(&self, txt: &str) -> Option<usize> {
        let n = txt.len();
        if n < self.m {
            return None;
        }

        let mut txt_hash = self.hash(txt, self.m);

        // check for match at offset 0
        if self.pat_hash == txt_hash && self.check(txt, 0) {
            return Some(0);
        }

        // check for hash match
        for i in self.m .. n {
            txt_hash = (txt_hash + self.q - self.rm * txt.char_at(i-self.m) as usize % self.q) % self.q;
            txt_hash = (txt_hash * self.r + txt.char_at(i) as usize) % self.q;

            let offset = i - self.m + 1;
            if self.pat_hash == txt_hash && self.check(txt, offset) {
                return Some(offset);
            }
        }
        None
    }

    fn long_random_prime() -> usize {
        // TODO: max bits 31, use random prime generator
        5800079
    }
}

#[test]
fn test_rabin_karp() {
    let pat = "abracadabra";
    let text = "abacadabrabracabracadabrabrabracad";
    let bm = RabinKarp::new(pat);
    assert!(bm.search(text).map_or(false, |pos| text[pos..].starts_with(pat)));
    assert_eq!(bm.search("zzzzz"), None);
}
<|endoftext|>