<commit_before>/* 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/. */

#![allow(uppercase_variables)]

extern crate freetype;
extern crate fontconfig;

use fontconfig::fontconfig::{
    FcChar8, FcResultMatch, FcSetSystem, FcPattern,
    FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD, FC_SLANT_OBLIQUE
};
use fontconfig::fontconfig::{
    FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
    FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
    FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
    FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
    FcObjectSetAdd, FcPatternGetInteger
};

use style::computed_values::font_style;

use font::{FontHandleMethods, UsedFontStyle};
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;

use collections::HashMap;
use libc;
use libc::{c_int, c_char};
use std::ptr;
use std::str;

pub struct FontListHandle {
    pub fctx: FontContextHandle,
}

impl FontListHandle {
    pub fn new(fctx: &FontContextHandle) -> FontListHandle {
        FontListHandle { fctx: fctx.clone() }
    }

    pub fn get_available_families(&self) -> FontFamilyMap {
        let mut family_map : FontFamilyMap = HashMap::new();
        unsafe {
            let config = FcConfigGetCurrent();
            let fontSet = FcConfigGetFonts(config, FcSetSystem);
            for i in range(0, (*fontSet).nfont as int) {
                let font = (*fontSet).fonts.offset(i);
                let family: *FcChar8 = ptr::null();
                let mut v: c_int = 0;
                "family".to_c_str().with_ref(|FC_FAMILY| {
                    while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
                        let family_name = str::raw::from_c_str(family as *c_char);
                        debug!("Creating new FontFamily for family: {:s}", family_name);
                        let new_family = FontFamily::new(family_name.as_slice());
                        family_map.insert(family_name, new_family);
                        v += 1;
                    }
                });
            }
        }
        return family_map;
    }

    pub fn load_variations_for_family(&self, family: &mut FontFamily) {
        debug!("getting variations for {:?}", family);
        unsafe {
            let config = FcConfigGetCurrent();
            let font_set = FcConfigGetFonts(config, FcSetSystem);
            let font_set_array_ptr = &font_set;
            let pattern = FcPatternCreate();
            assert!(pattern.is_not_null());
            "family".to_c_str().with_ref(|FC_FAMILY| {
                family.family_name.to_c_str().with_ref(|family_name| {
                    let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
                    assert!(ok != 0);
                });
            });

            let object_set = FcObjectSetCreate();
            assert!(object_set.is_not_null());

            "file".to_c_str().with_ref(|FC_FILE| {
                FcObjectSetAdd(object_set, FC_FILE);
            });
            "index".to_c_str().with_ref(|FC_INDEX| {
                FcObjectSetAdd(object_set, FC_INDEX);
            });

            let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);

            debug!("found {} variations", (*matches).nfont);

            for i in range(0, (*matches).nfont as int) {
                let font = (*matches).fonts.offset(i);
                let file = "file".to_c_str().with_ref(|FC_FILE| {
                    let file: *FcChar8 = ptr::null();
                    if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
                        str::raw::from_c_str(file as *libc::c_char)
                    } else {
                        fail!();
                    }
                });
                let index = "index".to_c_str().with_ref(|FC_INDEX| {
                    let index: libc::c_int = 0;
                    if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
                        index
                    } else {
                        fail!();
                    }
                });

                debug!("variation file: {}", file);
                debug!("variation index: {}", index);

                let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
                                                                     file);
                let font_handle = font_handle.unwrap();

                debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
                let entry = FontEntry::new(font_handle);
                family.entries.push(entry);
            }

            FcFontSetDestroy(matches);
            FcPatternDestroy(pattern);
            FcObjectSetDestroy(object_set);
        }
    }

    pub fn get_last_resort_font_families() -> Vec<String> {
        vec!("Arial".to_string())
    }
}

struct AutoPattern {
    pattern: *FcPattern
}

impl Drop for AutoPattern {
    fn drop(&mut self) {
        unsafe {
            FcPatternDestroy(self.pattern);
        }
    }
}

pub fn path_from_identifier(name: String, style: &UsedFontStyle) -> Result<String, ()> {
    unsafe {
        let config = FcConfigGetCurrent();
        let wrapper = AutoPattern { pattern: FcPatternCreate() };
        let pattern = wrapper.pattern;
        let res = "family".to_c_str().with_ref(|FC_FAMILY| {
            name.to_c_str().with_ref(|family| {
                FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
            })
        });
        if res != 1 {
            debug!("adding family to pattern failed");
            return Err(());
        }

        match style.style {
            font_style::normal => (),
            font_style::italic => {
                let res = "slant".to_c_str().with_ref(|FC_SLANT| {
                    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
                });
                if res != 1 {
                    debug!("adding slant to pattern failed");
                    return Err(());
                }
            },
            font_style::oblique => {
                let res = "slant".to_c_str().with_ref(|FC_SLANT| {
                    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
                });
                if res != 1 {
                    debug!("adding slant(oblique) to pattern failed");
                    return Err(());
                }
            }
        }

        if style.weight.is_bold() {
            let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
                FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
            });
            if res != 1 {
                debug!("adding weight to pattern failed");
                return Err(());
            }
        }

        if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
            debug!("substitution failed");
            return Err(());
        }
        FcDefaultSubstitute(pattern);
        let result = FcResultNoMatch;
        let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
        let result_pattern = result_wrapper.pattern;
        if result != FcResultMatch && result_pattern.is_null() {
            debug!("obtaining match to pattern failed");
            return Err(());
        }

        let file: *FcChar8 = ptr::null();
        let res = "file".to_c_str().with_ref(|FC_FILE| {
            FcPatternGetString(result_pattern, FC_FILE, 0, &file)
        });
        if res != FcResultMatch {
            debug!("getting filename for font failed");
            return Err(());
        }
        Ok(str::raw::from_c_str(file as *c_char))
    }
}
<commit_msg>Add Fira Sans and DejaVu Sans to the last-resort font families.<commit_after>/* 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/. */

#![allow(uppercase_variables)]

extern crate freetype;
extern crate fontconfig;

use fontconfig::fontconfig::{
    FcChar8, FcResultMatch, FcSetSystem, FcPattern,
    FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD, FC_SLANT_OBLIQUE
};
use fontconfig::fontconfig::{
    FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
    FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
    FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
    FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
    FcObjectSetAdd, FcPatternGetInteger
};

use style::computed_values::font_style;

use font::{FontHandleMethods, UsedFontStyle};
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;

use collections::HashMap;
use libc;
use libc::{c_int, c_char};
use std::ptr;
use std::str;

pub struct FontListHandle {
    pub fctx: FontContextHandle,
}

impl FontListHandle {
    pub fn new(fctx: &FontContextHandle) -> FontListHandle {
        FontListHandle { fctx: fctx.clone() }
    }

    pub fn get_available_families(&self) -> FontFamilyMap {
        let mut family_map : FontFamilyMap = HashMap::new();
        unsafe {
            let config = FcConfigGetCurrent();
            let fontSet = FcConfigGetFonts(config, FcSetSystem);
            for i in range(0, (*fontSet).nfont as int) {
                let font = (*fontSet).fonts.offset(i);
                let family: *FcChar8 = ptr::null();
                let mut v: c_int = 0;
                "family".to_c_str().with_ref(|FC_FAMILY| {
                    while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
                        let family_name = str::raw::from_c_str(family as *c_char);
                        debug!("Creating new FontFamily for family: {:s}", family_name);
                        let new_family = FontFamily::new(family_name.as_slice());
                        family_map.insert(family_name, new_family);
                        v += 1;
                    }
                });
            }
        }
        return family_map;
    }

    pub fn load_variations_for_family(&self, family: &mut FontFamily) {
        debug!("getting variations for {:?}", family);
        unsafe {
            let config = FcConfigGetCurrent();
            let font_set = FcConfigGetFonts(config, FcSetSystem);
            let font_set_array_ptr = &font_set;
            let pattern = FcPatternCreate();
            assert!(pattern.is_not_null());
            "family".to_c_str().with_ref(|FC_FAMILY| {
                family.family_name.to_c_str().with_ref(|family_name| {
                    let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
                    assert!(ok != 0);
                });
            });

            let object_set = FcObjectSetCreate();
            assert!(object_set.is_not_null());

            "file".to_c_str().with_ref(|FC_FILE| {
                FcObjectSetAdd(object_set, FC_FILE);
            });
            "index".to_c_str().with_ref(|FC_INDEX| {
                FcObjectSetAdd(object_set, FC_INDEX);
            });

            let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);

            debug!("found {} variations", (*matches).nfont);

            for i in range(0, (*matches).nfont as int) {
                let font = (*matches).fonts.offset(i);
                let file = "file".to_c_str().with_ref(|FC_FILE| {
                    let file: *FcChar8 = ptr::null();
                    if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
                        str::raw::from_c_str(file as *libc::c_char)
                    } else {
                        fail!();
                    }
                });
                let index = "index".to_c_str().with_ref(|FC_INDEX| {
                    let index: libc::c_int = 0;
                    if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
                        index
                    } else {
                        fail!();
                    }
                });

                debug!("variation file: {}", file);
                debug!("variation index: {}", index);

                let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
                                                                     file);
                let font_handle = font_handle.unwrap();

                debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
                let entry = FontEntry::new(font_handle);
                family.entries.push(entry);
            }

            FcFontSetDestroy(matches);
            FcPatternDestroy(pattern);
            FcObjectSetDestroy(object_set);
        }
    }

    pub fn get_last_resort_font_families() -> Vec<String> {
        vec!(
            "Fira Sans".to_string(),
            "DejaVu Sans".to_string(),
            "Arial".to_string()
        )
    }
}

struct AutoPattern {
    pattern: *FcPattern
}

impl Drop for AutoPattern {
    fn drop(&mut self) {
        unsafe {
            FcPatternDestroy(self.pattern);
        }
    }
}

pub fn path_from_identifier(name: String, style: &UsedFontStyle) -> Result<String, ()> {
    unsafe {
        let config = FcConfigGetCurrent();
        let wrapper = AutoPattern { pattern: FcPatternCreate() };
        let pattern = wrapper.pattern;
        let res = "family".to_c_str().with_ref(|FC_FAMILY| {
            name.to_c_str().with_ref(|family| {
                FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
            })
        });
        if res != 1 {
            debug!("adding family to pattern failed");
            return Err(());
        }

        match style.style {
            font_style::normal => (),
            font_style::italic => {
                let res = "slant".to_c_str().with_ref(|FC_SLANT| {
                    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
                });
                if res != 1 {
                    debug!("adding slant to pattern failed");
                    return Err(());
                }
            },
            font_style::oblique => {
                let res = "slant".to_c_str().with_ref(|FC_SLANT| {
                    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
                });
                if res != 1 {
                    debug!("adding slant(oblique) to pattern failed");
                    return Err(());
                }
            }
        }

        if style.weight.is_bold() {
            let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
                FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
            });
            if res != 1 {
                debug!("adding weight to pattern failed");
                return Err(());
            }
        }

        if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
            debug!("substitution failed");
            return Err(());
        }
        FcDefaultSubstitute(pattern);
        let result = FcResultNoMatch;
        let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
        let result_pattern = result_wrapper.pattern;
        if result != FcResultMatch && result_pattern.is_null() {
            debug!("obtaining match to pattern failed");
            return Err(());
        }

        let file: *FcChar8 = ptr::null();
        let res = "file".to_c_str().with_ref(|FC_FILE| {
            FcPatternGetString(result_pattern, FC_FILE, 0, &file)
        });
        if res != FcResultMatch {
            debug!("getting filename for font failed");
            return Err(());
        }
        Ok(str::raw::from_c_str(file as *c_char))
    }
}
<|endoftext|>


<commit_before>use std::convert::TryInto;

use crate::email_address::EmailAddress;
use crate::utils::agent::Message;

#[cfg(feature = "lettre")]
use ::lettre::message::{Message as LettreMessage, MultiPart};

/// Message requesting a mail be sent.
///
/// Handlers should also time the request using `metrics::AUTH_EMAIL_SEND_DURATION`, measuring the
/// narrowest possible section of code that makes the external call.
pub struct SendMail {
    pub to: EmailAddress,
    pub subject: String,
    pub html_body: String,
    pub text_body: String,
}
impl Message for SendMail {
    type Reply = bool;
}

#[cfg(feature = "lettre")]
impl SendMail {
    /// Convert the message to a Lettre `Message`.
    pub fn into_lettre_message(
        self,
        from_address: &EmailAddress,
        from_name: &str,
    ) -> LettreMessage {
        LettreMessage::builder()
            .from(
                (from_name, from_address.as_str())
                    .try_into()
                    .expect("Could not build mail From header"),
            )
            .to(self
                .to
                .as_str()
                .parse()
                .expect("Could not build mail To header"))
            .subject(self.subject)
            .multipart(MultiPart::alternative_plain_html(
                self.text_body,
                self.html_body,
            ))
            .expect("Could not build mail")
    }
}

#[cfg(feature = "lettre_smtp")]
pub mod lettre_smtp;
#[cfg(feature = "lettre_smtp")]
pub use self::lettre_smtp::SmtpMailer;

#[cfg(feature = "lettre_sendmail")]
pub mod lettre_sendmail;
#[cfg(feature = "lettre_sendmail")]
pub use self::lettre_sendmail::SendmailMailer;

#[cfg(feature = "postmark")]
pub mod postmark;
#[cfg(feature = "postmark")]
pub use self::postmark::PostmarkMailer;

#[cfg(feature = "mailgun")]
pub mod mailgun;
#[cfg(feature = "mailgun")]
pub use self::mailgun::MailgunMailer;
<commit_msg>Parse email as lettre Address, not Mailbox<commit_after>use std::convert::TryInto;

use crate::email_address::EmailAddress;
use crate::utils::agent::Message;

#[cfg(feature = "lettre")]
use ::lettre::message::{Mailbox, Message as LettreMessage, MultiPart};

/// Message requesting a mail be sent.
///
/// Handlers should also time the request using `metrics::AUTH_EMAIL_SEND_DURATION`, measuring the
/// narrowest possible section of code that makes the external call.
pub struct SendMail {
    pub to: EmailAddress,
    pub subject: String,
    pub html_body: String,
    pub text_body: String,
}
impl Message for SendMail {
    type Reply = bool;
}

#[cfg(feature = "lettre")]
impl SendMail {
    /// Convert the message to a Lettre `Message`.
    pub fn into_lettre_message(
        self,
        from_address: &EmailAddress,
        from_name: &str,
    ) -> LettreMessage {
        LettreMessage::builder()
            .from(
                (from_name, from_address.as_str())
                    .try_into()
                    .expect("Could not build mail From header"),
            )
            .to(Mailbox::new(
                None,
                self.to
                    .as_str()
                    .parse()
                    .expect("Could not build mail To header"),
            ))
            .subject(self.subject)
            .multipart(MultiPart::alternative_plain_html(
                self.text_body,
                self.html_body,
            ))
            .expect("Could not build mail")
    }
}

#[cfg(feature = "lettre_smtp")]
pub mod lettre_smtp;
#[cfg(feature = "lettre_smtp")]
pub use self::lettre_smtp::SmtpMailer;

#[cfg(feature = "lettre_sendmail")]
pub mod lettre_sendmail;
#[cfg(feature = "lettre_sendmail")]
pub use self::lettre_sendmail::SendmailMailer;

#[cfg(feature = "postmark")]
pub mod postmark;
#[cfg(feature = "postmark")]
pub use self::postmark::PostmarkMailer;

#[cfg(feature = "mailgun")]
pub mod mailgun;
#[cfg(feature = "mailgun")]
pub use self::mailgun::MailgunMailer;
<|endoftext|>


<commit_before>
use CreationError;
use GlAttributes;
use GlProfile;
use GlRequest;
use PixelFormatRequirements;
use ReleaseBehavior;
use cocoa::appkit::*;

pub fn build_nsattributes<T>(pf_reqs: &PixelFormatRequirements, opengl: &GlAttributes<&T>)
    -> Result<Vec<u32>, CreationError> {

    let profile = match (opengl.version, opengl.version.to_gl_version(), opengl.profile) {

        // Note: we are not using ranges because of a rust bug that should be fixed here:
        // https://github.com/rust-lang/rust/pull/27050

        (GlRequest::Latest, _, Some(GlProfile::Compatibility)) => NSOpenGLProfileVersionLegacy as u32,
        (GlRequest::Latest, _, _) => unsafe {
            if NSAppKitVersionNumber.floor() >= NSAppKitVersionNumber10_9 {
                NSOpenGLProfileVersion4_1Core as u32
            } else if NSAppKitVersionNumber.floor() >= NSAppKitVersionNumber10_7 {
                NSOpenGLProfileVersion3_2Core as u32
            } else {
                NSOpenGLProfileVersionLegacy as u32
            }
        },

        (_, Some((1, _)), _) => NSOpenGLProfileVersionLegacy as u32,
        (_, Some((2, _)), _) => NSOpenGLProfileVersionLegacy as u32,
        (_, Some((3, 0)), _) => NSOpenGLProfileVersionLegacy as u32,
        (_, Some((3, 1)), _) => NSOpenGLProfileVersionLegacy as u32,
        (_, Some((3, 2)), _) => NSOpenGLProfileVersion3_2Core as u32,
        (_, Some((3, _)), Some(GlProfile::Compatibility)) => return Err(CreationError::OpenGlVersionNotSupported),
        (_, Some((3, _)), _) => NSOpenGLProfileVersion4_1Core as u32,
        (_, Some((4, _)), Some(GlProfile::Compatibility)) => return Err(CreationError::OpenGlVersionNotSupported),
        (_, Some((4, _)), _) => NSOpenGLProfileVersion4_1Core as u32,
        _ => return Err(CreationError::OpenGlVersionNotSupported),
    };

    // NOTE: OS X no longer has the concept of setting individual
    // color component's bit size. Instead we can only specify the
    // full color size and hope for the best. Another hiccup is that
    // `NSOpenGLPFAColorSize` also includes `NSOpenGLPFAAlphaSize`,
    // so we have to account for that as well.
    let alpha_depth = pf_reqs.alpha_bits.unwrap_or(8);
    let color_depth = pf_reqs.color_bits.unwrap_or(24) + alpha_depth;

    // TODO: handle hardware_accelerated parameter of pf_reqs

    let mut attributes = vec![
        NSOpenGLPFADoubleBuffer as u32,
        NSOpenGLPFAClosestPolicy as u32,
        NSOpenGLPFAColorSize as u32, color_depth as u32,
        NSOpenGLPFAAlphaSize as u32, alpha_depth as u32,
        NSOpenGLPFADepthSize as u32, pf_reqs.depth_bits.unwrap_or(24) as u32,
        NSOpenGLPFAStencilSize as u32, pf_reqs.stencil_bits.unwrap_or(8) as u32,
        NSOpenGLPFAOpenGLProfile as u32, profile,
    ];

    if pf_reqs.release_behavior != ReleaseBehavior::Flush {
        return Err(CreationError::NoAvailablePixelFormat);
    }

    if pf_reqs.stereoscopy {
        unimplemented!();   // TODO:
    }

    if pf_reqs.double_buffer == Some(false) {
        unimplemented!();   // TODO:
    }

    if pf_reqs.float_color_buffer {
        attributes.push(NSOpenGLPFAColorFloat as u32);
    }

    pf_reqs.multisampling.map(|samples| {
        attributes.push(NSOpenGLPFAMultisample as u32);
        attributes.push(NSOpenGLPFASampleBuffers as u32); attributes.push(1);
        attributes.push(NSOpenGLPFASamples as u32); attributes.push(samples as u32);
    });

    // attribute list must be null terminated.
    attributes.push(0);

    Ok(attributes)
}
<commit_msg>Auto merge of #137 - mstange:cherrypick-upstream-pr-894, r=jdm<commit_after>
use CreationError;
use GlAttributes;
use GlProfile;
use GlRequest;
use PixelFormatRequirements;
use ReleaseBehavior;
use cocoa::appkit::*;

pub fn build_nsattributes<T>(pf_reqs: &PixelFormatRequirements, opengl: &GlAttributes<&T>)
    -> Result<Vec<u32>, CreationError> {

    let profile = match (opengl.version, opengl.version.to_gl_version(), opengl.profile) {

        // Note: we are not using ranges because of a rust bug that should be fixed here:
        // https://github.com/rust-lang/rust/pull/27050

        (GlRequest::Latest, _, Some(GlProfile::Compatibility)) => NSOpenGLProfileVersionLegacy as u32,
        (GlRequest::Latest, _, _) => unsafe {
            if NSAppKitVersionNumber.floor() >= NSAppKitVersionNumber10_9 {
                NSOpenGLProfileVersion4_1Core as u32
            } else if NSAppKitVersionNumber.floor() >= NSAppKitVersionNumber10_7 {
                NSOpenGLProfileVersion3_2Core as u32
            } else {
                NSOpenGLProfileVersionLegacy as u32
            }
        },

        (_, Some((1, _)), _) => NSOpenGLProfileVersionLegacy as u32,
        (_, Some((2, _)), _) => NSOpenGLProfileVersionLegacy as u32,
        (_, Some((3, 0)), _) => NSOpenGLProfileVersionLegacy as u32,
        (_, Some((3, 1)), _) => NSOpenGLProfileVersionLegacy as u32,
        (_, Some((3, 2)), _) => NSOpenGLProfileVersion3_2Core as u32,
        (_, Some((3, _)), Some(GlProfile::Compatibility)) => return Err(CreationError::OpenGlVersionNotSupported),
        (_, Some((3, _)), _) => NSOpenGLProfileVersion4_1Core as u32,
        (_, Some((4, _)), Some(GlProfile::Compatibility)) => return Err(CreationError::OpenGlVersionNotSupported),
        (_, Some((4, _)), _) => NSOpenGLProfileVersion4_1Core as u32,
        _ => return Err(CreationError::OpenGlVersionNotSupported),
    };

    // NOTE: OS X no longer has the concept of setting individual
    // color component's bit size. Instead we can only specify the
    // full color size and hope for the best. Another hiccup is that
    // `NSOpenGLPFAColorSize` also includes `NSOpenGLPFAAlphaSize`,
    // so we have to account for that as well.
    let alpha_depth = pf_reqs.alpha_bits.unwrap_or(8);
    let color_depth = pf_reqs.color_bits.unwrap_or(24) + alpha_depth;

    // TODO: handle hardware_accelerated parameter of pf_reqs

    let mut attributes = vec![
        NSOpenGLPFADoubleBuffer as u32,
        NSOpenGLPFAClosestPolicy as u32,
        NSOpenGLPFAColorSize as u32, color_depth as u32,
        NSOpenGLPFAAlphaSize as u32, alpha_depth as u32,
        NSOpenGLPFADepthSize as u32, pf_reqs.depth_bits.unwrap_or(24) as u32,
        NSOpenGLPFAStencilSize as u32, pf_reqs.stencil_bits.unwrap_or(8) as u32,
        NSOpenGLPFAAllowOfflineRenderers as u32,
        NSOpenGLPFAOpenGLProfile as u32, profile,
    ];

    if pf_reqs.release_behavior != ReleaseBehavior::Flush {
        return Err(CreationError::NoAvailablePixelFormat);
    }

    if pf_reqs.stereoscopy {
        unimplemented!();   // TODO:
    }

    if pf_reqs.double_buffer == Some(false) {
        unimplemented!();   // TODO:
    }

    if pf_reqs.float_color_buffer {
        attributes.push(NSOpenGLPFAColorFloat as u32);
    }

    pf_reqs.multisampling.map(|samples| {
        attributes.push(NSOpenGLPFAMultisample as u32);
        attributes.push(NSOpenGLPFASampleBuffers as u32); attributes.push(1);
        attributes.push(NSOpenGLPFASamples as u32); attributes.push(samples as u32);
    });

    // attribute list must be null terminated.
    attributes.push(0);

    Ok(attributes)
}
<|endoftext|>


<commit_before>use serde::{Deserialize, Serialize};

/// Trait represents global state of the
/// entire simulation which can updated
/// independently from any particular cell.
/// Consider to store there as much as you can
/// because this data will be created only once
/// and will not be copied.
pub trait EvolutionState {
    /// Method is called once between cells' updates.
    fn update(&mut self);
}

pub trait Cell: Serialize + Deserialize {
    type Coord: Coord;
    type State: EvolutionState;

    fn update<'a, I>(&'a mut self, old: &'a Self, neighbors: I, &Self::State)
        where I: Iterator<Item = Option<&'a Self>>;

    fn with_coord<C: Coord>(C) -> Self;
    fn coord(&self) -> &Self::Coord;
    fn set_coord<C: Coord>(&mut self, &C);
}

pub trait Nhood {
    type Coord: Coord;

    fn neighbors(&self, &Self::Coord) -> Vec<Self::Coord>;
    fn neighbors_count(&self) -> usize;
}

pub trait Coord: Clone + Serialize + Deserialize {
    fn from_2d(x: i32, y: i32) -> Self;

    fn x(&self) -> i32;
    fn y(&self) -> i32;
    fn z(&self) -> i32 { 0 }
}

pub trait Grid {
    type Cell: Cell;
    type Coord: Coord;

    fn update(&mut self);

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State;
    fn cells(&self) -> &Vec<Self::Cell>;
    fn dimensions(&self) -> Self::Coord;

    fn set_cells(&mut self, Vec<Self::Cell>);
}

/// Interface to the outer world.
pub trait Consumer {
    /// Cells supported by this consumer. Helps
    /// to use cells from grid directly if grid
    /// has the same cell in it.
    type Cell: Cell;

    /// Called once when all cells has been updated.
    fn consume<G>(&mut self, &mut G)
        where G: Grid<Cell = Self::Cell>;
}

/// Interlayer between grid and consumer(s).
pub trait Engine {
    fn run_times(&mut self, i64);
}
<commit_msg>Note about Coord.<commit_after>use serde::{Deserialize, Serialize};

/// Trait represents global state of the
/// entire simulation which can updated
/// independently from any particular cell.
/// Consider to store there as much as you can
/// because this data will be created only once
/// and will not be copied.
pub trait EvolutionState {
    /// Method is called once between cells' updates.
    fn update(&mut self);
}

pub trait Cell: Serialize + Deserialize {
    type Coord: Coord;
    type State: EvolutionState;

    fn update<'a, I>(&'a mut self, old: &'a Self, neighbors: I, &Self::State)
        where I: Iterator<Item = Option<&'a Self>>;

    fn with_coord<C: Coord>(C) -> Self;
    fn coord(&self) -> &Self::Coord;
    fn set_coord<C: Coord>(&mut self, &C);
}

pub trait Nhood {
    type Coord: Coord;

    fn neighbors(&self, &Self::Coord) -> Vec<Self::Coord>;
    fn neighbors_count(&self) -> usize;
}

/// Basic coordinate with three components.
/// This crate is used for creating automata
/// on 2D grids for now, so `z` has default impl.
pub trait Coord: Clone + Serialize + Deserialize {
    /// Build coord from any other representation of coord.
    fn from_2d(x: i32, y: i32) -> Self;

    /// Returns `x` component.
    fn x(&self) -> i32;
    /// Returns `y` component.
    fn y(&self) -> i32;
    /// Returns `z` component.
    fn z(&self) -> i32 { 0 }
}

pub trait Grid {
    type Cell: Cell;
    type Coord: Coord;

    fn update(&mut self);

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State;
    fn cells(&self) -> &Vec<Self::Cell>;
    fn dimensions(&self) -> Self::Coord;

    fn set_cells(&mut self, Vec<Self::Cell>);
}

/// Interface to the outer world.
pub trait Consumer {
    /// Cells supported by this consumer. Helps
    /// to use cells from grid directly if grid
    /// has the same cell in it.
    type Cell: Cell;

    /// Called once when all cells has been updated.
    fn consume<G>(&mut self, &mut G)
        where G: Grid<Cell = Self::Cell>;
}

/// Interlayer between grid and consumer(s).
pub trait Engine {
    fn run_times(&mut self, i64);
}
<|endoftext|>


<commit_before>use ::num_traits::Float;

/// Representation of a mathematical vector e.g. a position or velocity
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Vector2<T>(pub T, pub T);

use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, Div, Neg};
use std::convert::From;

impl<T: Float> Vector2<T>{
    /// Creates a new unit vector in a specific direction
    pub fn unit_vector(direction: T) -> Self{
        let (y, x) = direction.sin_cos();
        Vector2(x, y)
    }
    /// Normalises the vector
    pub fn normalise(self) -> Self{
        self / self.length()
    }
    /// Returns the magnitude or the length of the vector
    pub fn length(self) -> T{
        self.0.hypot(self.1)
    }
    /// Returns direction the vector is pointing
    pub fn direction(self) -> T{
        (-self.1).atan2(self.0)
    }
    /// Returns direction towards another vector
    pub fn direction_to(self, other: Self) -> T{
        (other-self).direction()
    }
    /// Returns the distance betweens two vectors
    pub fn distance_to(self, other: Self) -> T{
        (self-other).length()
    }
}

macro_rules! impl_for {
    ($($t:ty)*) => {$(
        impl Mul<Vector2<$t>> for $t{
            type Output = Vector2<$t>;

            fn mul(self, rhs: Vector2<$t>) -> Vector2<$t>{
                Vector2(self * rhs.0, self * rhs.1)
            }
        }
        impl Div<Vector2<$t>> for $t{
            type Output = Vector2<$t>;

            fn div(self, rhs: Vector2<$t>) -> Vector2<$t>{
                Vector2(self / rhs.0, self / rhs.1)
            }
        }
    )*};
}impl_for!{f32 f64}

impl<T> Vector2<T> {
    /// Returns the dot product of two vectors
    pub fn dot(self, other: Self) -> T where T: Mul<Output=T> + Add<Output=T>{
        self.0 * other.0 + self.1 * other.1
    }
}

impl<T: Add<Output=T>> Add for Vector2<T>{
    type Output = Self;

    fn add(self, rhs: Self) -> Self{
        Vector2(self.0 + rhs.0, self.1 + rhs.1)
    }
}

impl<T: Sub<Output=T>> Sub for Vector2<T>{
    type Output = Self;

    fn sub(self, rhs: Self) -> Self{
        Vector2(self.0 - rhs.0, self.1 - rhs.1)
    }
}

impl<T: AddAssign> AddAssign for Vector2<T>{
    fn add_assign(&mut self, rhs: Self){
        self.0 += rhs.0;
        self.1 += rhs.1;
    }
}

impl<T: SubAssign> SubAssign for Vector2<T>{
    fn sub_assign(&mut self, rhs: Self){
        self.0 -= rhs.0;
        self.1 -= rhs.1;
    }
}

impl<T: Mul<Output=T> + Copy> Mul<T> for Vector2<T>{
    type Output = Self;

    fn mul(self, rhs: T) -> Self{
        Vector2(self.0 * rhs, self.1 * rhs)
    }
}

impl<T: Div<Output=T> + Copy> Div<T> for Vector2<T>{
    type Output = Self;

    fn div(self, rhs: T) -> Self{
        Vector2(self.0/rhs, self.1/rhs)
    }
}

impl<T: Neg<Output=T>> Neg for Vector2<T>{
    type Output = Self;

    fn neg(self) -> Self{
        Vector2(-self.0, -self.1)
    }
}

impl<T> Into<[T; 2]> for Vector2<T>{
    #[inline(always)]
    fn into(self) -> [T; 2]{
        [self.0, self.1]
    }
}

impl<T: Copy> From<[T; 2]> for Vector2<T>{
    #[inline(always)]
    fn from(array: [T; 2]) -> Self{
        Vector2(array[0], array[1])
    }
}

impl<T> Into<(T, T)> for Vector2<T>{
    #[inline(always)]
    fn into(self) -> (T, T){
        (self.0, self.1)
    }
}

impl<T> From<(T, T)> for Vector2<T>{
    #[inline(always)]
    fn from(tuple: (T, T)) -> Self{
        Vector2(tuple.0, tuple.1)
    }
}
<commit_msg>Fix Vectors?<commit_after>use ::num_traits::Float;

/// Representation of a mathematical vector e.g. a position or velocity
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Vector2<T>(pub T, pub T);

use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, Div, Neg};
use std::convert::From;

impl<T: Float> Vector2<T>{
    /// Creates a new unit vector in a specific direction
    pub fn unit_vector(direction: T) -> Self{
        let (y, x) = direction.sin_cos();
        Vector2(x, y)
    }
    /// Normalises the vector
    pub fn normalise(self) -> Self{
        self / self.length()
    }
    /// Returns the magnitude or the length of the vector
    pub fn length(self) -> T{
        self.0.hypot(self.1)
    }
    /// Returns direction the vector is pointing
    pub fn direction(self) -> T{
        self.1.atan2(self.0)
    }
    /// Returns direction towards another vector
    pub fn direction_to(self, other: Self) -> T{
        (other-self).direction()
    }
    /// Returns the distance betweens two vectors
    pub fn distance_to(self, other: Self) -> T{
        (self-other).length()
    }
}

macro_rules! impl_for {
    ($($t:ty)*) => {$(
        impl Mul<Vector2<$t>> for $t{
            type Output = Vector2<$t>;

            fn mul(self, rhs: Vector2<$t>) -> Vector2<$t>{
                Vector2(self * rhs.0, self * rhs.1)
            }
        }
        impl Div<Vector2<$t>> for $t{
            type Output = Vector2<$t>;

            fn div(self, rhs: Vector2<$t>) -> Vector2<$t>{
                Vector2(self / rhs.0, self / rhs.1)
            }
        }
    )*};
}impl_for!{f32 f64}

impl<T> Vector2<T> {
    /// Returns the dot product of two vectors
    pub fn dot(self, other: Self) -> T where T: Mul<Output=T> + Add<Output=T>{
        self.0 * other.0 + self.1 * other.1
    }
}

impl<T: Add<Output=T>> Add for Vector2<T>{
    type Output = Self;

    fn add(self, rhs: Self) -> Self{
        Vector2(self.0 + rhs.0, self.1 + rhs.1)
    }
}

impl<T: Sub<Output=T>> Sub for Vector2<T>{
    type Output = Self;

    fn sub(self, rhs: Self) -> Self{
        Vector2(self.0 - rhs.0, self.1 - rhs.1)
    }
}

impl<T: AddAssign> AddAssign for Vector2<T>{
    fn add_assign(&mut self, rhs: Self){
        self.0 += rhs.0;
        self.1 += rhs.1;
    }
}

impl<T: SubAssign> SubAssign for Vector2<T>{
    fn sub_assign(&mut self, rhs: Self){
        self.0 -= rhs.0;
        self.1 -= rhs.1;
    }
}

impl<T: Mul<Output=T> + Copy> Mul<T> for Vector2<T>{
    type Output = Self;

    fn mul(self, rhs: T) -> Self{
        Vector2(self.0 * rhs, self.1 * rhs)
    }
}

impl<T: Div<Output=T> + Copy> Div<T> for Vector2<T>{
    type Output = Self;

    fn div(self, rhs: T) -> Self{
        Vector2(self.0/rhs, self.1/rhs)
    }
}

impl<T: Neg<Output=T>> Neg for Vector2<T>{
    type Output = Self;

    fn neg(self) -> Self{
        Vector2(-self.0, -self.1)
    }
}

impl<T> Into<[T; 2]> for Vector2<T>{
    #[inline(always)]
    fn into(self) -> [T; 2]{
        [self.0, self.1]
    }
}

impl<T: Copy> From<[T; 2]> for Vector2<T>{
    #[inline(always)]
    fn from(array: [T; 2]) -> Self{
        Vector2(array[0], array[1])
    }
}

impl<T> Into<(T, T)> for Vector2<T>{
    #[inline(always)]
    fn into(self) -> (T, T){
        (self.0, self.1)
    }
}

impl<T> From<(T, T)> for Vector2<T>{
    #[inline(always)]
    fn from(tuple: (T, T)) -> Self{
        Vector2(tuple.0, tuple.1)
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate libc;
extern crate nix;
extern crate env_logger;
extern crate regex;
extern crate argparse;
extern crate quire;
#[macro_use] extern crate log;
extern crate lithos;

use std::env;
use std::io::{stderr, Read, Write};
use std::process::exit;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::fs::{File};
use std::fs::{copy, rename};
use std::default::Default;
use std::process::{Command, Stdio};

use argparse::{ArgumentParser, Parse, StoreTrue, Print};
use quire::parse_config;
use nix::sys::signal::{SIGQUIT, kill};

use lithos::master_config::MasterConfig;
use lithos::sandbox_config::SandboxConfig;

fn switch_config(master_cfg: &Path, sandbox_name: String, config_file: &Path)
    -> Result<(), String>
{
    match Command::new(env::current_exe().unwrap()
                       .parent().unwrap().join("lithos_check"))
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .arg("--config")
        .arg(&master_cfg)
        .arg("--sandbox")
        .arg(&sandbox_name)
        .arg("--alternate-config")
        .arg(&config_file)
        .output()
    {
        Ok(ref po) if po.status.code() == Some(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &MasterConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let sandbox_fn = master_cfg.parent().unwrap()
        .join(&master.sandboxes_dir)
        .join(&(sandbox_name.clone() + ".yaml"));
    let sandbox: SandboxConfig = match parse_config(&sandbox_fn,
        &SandboxConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse sandbox config: {}", e));
        }
    };

    let target_fn = master_cfg.parent().unwrap()
        .join(&master.processes_dir)
        .join(sandbox.config_file.as_ref().unwrap_or(
            &PathBuf::from(&(sandbox_name.clone() + ".yaml"))));
    debug!("Target filename {:?}", target_fn);
    let tmp_filename = target_fn.with_file_name(
        &format!(".tmp.{}", sandbox_name));
    try!(copy(&config_file, &tmp_filename)
        .map_err(|e| format!("Error copying: {}", e)));
    try!(rename(&tmp_filename, &target_fn)
        .map_err(|e| format!("Error replacing file: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    let mut buf = String::with_capacity(50);
    let read = File::open(&pid_file)
            .and_then(|mut f| f.read_to_string(&mut buf))
            .ok();
    match read.and_then(|_| FromStr::from_str(buf[..].trim()).ok()) {
        Some(pid) if kill(pid, 0).is_ok() => {
            kill(pid, SIGQUIT)
            .map_err(|e| error!("Error sending QUIT to master: {:?}", e)).ok();
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}

fn main() {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "warn");
    }
    env_logger::init().unwrap();

    let mut master_config = PathBuf::from("/etc/lithos/master.yaml");
    let mut verbose = false;
    let mut config_file = PathBuf::from("");
    let mut sandbox_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(&["--master"], Parse,
            "Name of the master configuration file \
                (default /etc/lithos/master.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(&["-v", "--verbose"], StoreTrue,
            "Verbose configuration");
        ap.refer(&mut sandbox_name)
          .add_argument("sandbox", Parse,
            "Name of the sandbox which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_file)
          .add_argument("new_config", Parse, "
            Name of the configuration directory to switch to. It doesn't
            have to be a directory inside `config-dir`, and it will be copied
            there. However, if directory with the same name exists in the
            `config-dir` it's assumed that it's already copied and will not
            be updated. Be sure to use unique directory for each deployment.
            ")
          .metavar("FILE")
          .required();
        ap.add_option(&["--version"],
            Print(env!("CARGO_PKG_VERSION").to_string()),
            "Show version");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }
    match switch_config(&master_config, sandbox_name, &config_file)
    {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            write!(&mut stderr(), "Fatal error: {}\n", e).unwrap();
            exit(1);
        }
    }
}
<commit_msg>Fix option description of lithos_switch<commit_after>extern crate rustc_serialize;
extern crate libc;
extern crate nix;
extern crate env_logger;
extern crate regex;
extern crate argparse;
extern crate quire;
#[macro_use] extern crate log;
extern crate lithos;

use std::env;
use std::io::{stderr, Read, Write};
use std::process::exit;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::fs::{File};
use std::fs::{copy, rename};
use std::default::Default;
use std::process::{Command, Stdio};

use argparse::{ArgumentParser, Parse, StoreTrue, Print};
use quire::parse_config;
use nix::sys::signal::{SIGQUIT, kill};

use lithos::master_config::MasterConfig;
use lithos::sandbox_config::SandboxConfig;

fn switch_config(master_cfg: &Path, sandbox_name: String, config_file: &Path)
    -> Result<(), String>
{
    match Command::new(env::current_exe().unwrap()
                       .parent().unwrap().join("lithos_check"))
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .arg("--config")
        .arg(&master_cfg)
        .arg("--sandbox")
        .arg(&sandbox_name)
        .arg("--alternate-config")
        .arg(&config_file)
        .output()
    {
        Ok(ref po) if po.status.code() == Some(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &MasterConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let sandbox_fn = master_cfg.parent().unwrap()
        .join(&master.sandboxes_dir)
        .join(&(sandbox_name.clone() + ".yaml"));
    let sandbox: SandboxConfig = match parse_config(&sandbox_fn,
        &SandboxConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse sandbox config: {}", e));
        }
    };

    let target_fn = master_cfg.parent().unwrap()
        .join(&master.processes_dir)
        .join(sandbox.config_file.as_ref().unwrap_or(
            &PathBuf::from(&(sandbox_name.clone() + ".yaml"))));
    debug!("Target filename {:?}", target_fn);
    let tmp_filename = target_fn.with_file_name(
        &format!(".tmp.{}", sandbox_name));
    try!(copy(&config_file, &tmp_filename)
        .map_err(|e| format!("Error copying: {}", e)));
    try!(rename(&tmp_filename, &target_fn)
        .map_err(|e| format!("Error replacing file: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    let mut buf = String::with_capacity(50);
    let read = File::open(&pid_file)
            .and_then(|mut f| f.read_to_string(&mut buf))
            .ok();
    match read.and_then(|_| FromStr::from_str(buf[..].trim()).ok()) {
        Some(pid) if kill(pid, 0).is_ok() => {
            kill(pid, SIGQUIT)
            .map_err(|e| error!("Error sending QUIT to master: {:?}", e)).ok();
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}

fn main() {
    if env::var("RUST_LOG").is_err() {
        env::set_var("RUST_LOG", "warn");
    }
    env_logger::init().unwrap();

    let mut master_config = PathBuf::from("/etc/lithos/master.yaml");
    let mut verbose = false;
    let mut config_file = PathBuf::from("");
    let mut sandbox_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(&["--master"], Parse,
            "Name of the master configuration file \
                (default /etc/lithos/master.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(&["-v", "--verbose"], StoreTrue,
            "Verbose configuration");
        ap.refer(&mut sandbox_name)
          .add_argument("sandbox", Parse,
            "Name of the sandbox which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_file)
          .add_argument("new_config", Parse, "
            Name of the configuration file to this sandbox switch to.
            The file is copied over current config after configuration is
            validated and just before sending a signal to lithos_tree.")
          .metavar("FILE")
          .required();
        ap.add_option(&["--version"],
            Print(env!("CARGO_PKG_VERSION").to_string()),
            "Show version");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }
    match switch_config(&master_config, sandbox_name, &config_file)
    {
        Ok(()) => {
            exit(0);
        }
        Err(e) => {
            write!(&mut stderr(), "Fatal error: {}\n", e).unwrap();
            exit(1);
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::f32::consts::PI;

use collect_slice::CollectSlice;

use consts::SAMPLES;
use descramble::VoiceDecisions;
use enhance::EnhancedSpectrals;
use noise::Noise;
use params::BaseParams;
use prev::PrevFrame;
use window;

pub struct PhaseBase([f32; 56]);

impl PhaseBase {
    pub fn new(params: &BaseParams, prev: &PrevFrame) -> PhaseBase {
        let mut phase_base = [0.0; 56];
        let common = (prev.params.fundamental + params.fundamental) *
            SAMPLES as f32 / 2.0;

        (1..57).map(|l| {
            prev.phase_base.get(l) + common * l as f32
        }).collect_slice_checked(&mut phase_base[..]);

        PhaseBase(phase_base)
    }

    pub fn get(&self, l: usize) -> f32 { self.0[l - 1] }
}

impl Default for PhaseBase {
    fn default() -> PhaseBase {
        PhaseBase([0.0; 56])
    }
}

pub struct Phase([f32; 56]);

impl Phase {
    pub fn new(params: &BaseParams, voice: &VoiceDecisions, base: &PhaseBase) -> Phase {
        let mut noise = Noise::new();
        let mut phase = [0.0; 56];

        let trans = params.harmonics as usize / 4;

        (1..trans+1).map(|l| {
            base.get(l)
        }).chain((trans+1..57).map(|l| {
            base.get(l) + voice.unvoiced_count as f32 * noise.next_phase() /
                params.harmonics as f32
        })).collect_slice_checked(&mut phase[..]);

        Phase(phase)
    }

    pub fn get(&self, l: usize) -> f32 { self.0[l - 1] }
}

impl Default for Phase {
    fn default() -> Phase {
        Phase([0.0; 56])
    }
}

pub struct Voiced<'a, 'b, 'c, 'd> {
    prev: &'a PrevFrame,
    phase: &'b Phase,
    enhanced: &'c EnhancedSpectrals,
    voice: &'d VoiceDecisions,
    window: window::Window,
    fundamental: f32,
    end: usize,
    freq_changed: bool,
}

impl<'a, 'b, 'c, 'd> Voiced<'a, 'b, 'c, 'd> {
    pub fn new(params: &BaseParams, prev: &'a PrevFrame, phase: &'b Phase,
               enhanced: &'c EnhancedSpectrals, voice: &'d VoiceDecisions)
        -> Voiced<'a, 'b, 'c, 'd>
    {
        let freq_diff = (params.fundamental - prev.params.fundamental).abs();

        Voiced {
            prev: prev,
            phase: phase,
            enhanced: enhanced,
            voice: voice,
            window: window::synthesis_full(),
            fundamental: params.fundamental,
            end: max(params.harmonics, prev.params.harmonics) as usize + 1,
            freq_changed: freq_diff >= 0.1 * params.fundamental,
        }
    }

    fn get_pair(&self, l: usize, n: isize) -> f32 {
        match (self.voice.is_voiced(l), self.prev.voice.is_voiced(l)) {
            (false, false) => 0.0,
            (false, true) => self.sig_prev(l, n),
            (true, false) => self.sig_cur(l, n),
            (true, true) => if l >= 8 || self.freq_changed {
                self.sig_prev(l, n) + self.sig_cur(l, n)
            } else {
                self.amplitude(l, n) * self.theta(l, n).cos()
            },
        }
    }

    fn sig_cur(&self, l: usize, n: isize) -> f32 {
        self.window.get(n - SAMPLES as isize) * self.enhanced.get(l) * (
            self.fundamental * (n - SAMPLES as isize) as f32 * l as f32 +
                self.phase.get(l)
        ).cos()
    }

    fn sig_prev(&self, l: usize, n: isize) -> f32 {
        self.window.get(n) * self.prev.enhanced.get(l) * (
            self.prev.params.fundamental * n as f32 * l as f32 +
                self.prev.phase.get(l)
        ).cos()
    }

    fn amplitude(&self, l: usize, n: isize) -> f32 {
        self.prev.enhanced.get(l) + n as f32 / SAMPLES as f32 *
            (self.enhanced.get(l) - self.prev.enhanced.get(l))
    }

    fn theta(&self, l: usize, n: isize) -> f32 {
        self.prev.phase.get(l) +
            (self.prev.params.fundamental * l as f32 + self.freq_change(l)) * n as f32 +
            (self.fundamental - self.prev.params.fundamental) *
                l as f32 * (n as f32).powi(2) / (2.0 * SAMPLES as f32)
    }

    fn phase_change(&self, l: usize) -> f32 {
        self.phase.get(l) - self.prev.phase.get(l) - (
            self.prev.params.fundamental + self.fundamental
        ) * l as f32 * SAMPLES as f32 / 2.0
    }

    fn freq_change(&self, l: usize) -> f32 {
        (SAMPLES as f32).recip() * (self.phase_change(l) - 2.0 * PI * (
            (self.phase_change(l) + PI) / (2.0 * PI)
        ).floor())
    }

    pub fn get(&self, n: usize) -> f32 {
        (1..self.end).map(|l| {
            2.0 * self.get_pair(l, n as isize)
        }).fold(0.0, |s, x| s + x)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use params::BaseParams;
    use prev::PrevFrame;
    use descramble::{descramble, Bootstrap};

    #[test]
    fn test_phase_base() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10101110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());
        let prev = PrevFrame::default();

        assert!((p.fundamental - 0.17575344).abs() < 0.000001);
        assert!((prev.params.fundamental - 0.0937765407).abs() < 0.000001);

        let pb = PhaseBase::new(&p, &prev);

        assert!((pb.get(1) - 21.56239846).abs() < 0.0001);
        assert!((pb.get(2) - 43.12479691).abs() < 0.0001);
        assert!((pb.get(3) - 64.68719537).abs() < 0.0001);
        assert!((pb.get(4) - 86.24959382).abs() < 0.0001);
        assert!((pb.get(5) - 107.8119923).abs() < 0.0001);
        assert!((pb.get(6) - 129.3743907).abs() < 0.0001);
        assert!((pb.get(20) - 431.2479691).abs() < 0.0001);
        assert!((pb.get(56) - 1207.494314).abs() < 0.001);
    }
}
<commit_msg>Hoist out multiplication<commit_after>use std::cmp::max;
use std::f32::consts::PI;

use collect_slice::CollectSlice;

use consts::SAMPLES;
use descramble::VoiceDecisions;
use enhance::EnhancedSpectrals;
use noise::Noise;
use params::BaseParams;
use prev::PrevFrame;
use window;

pub struct PhaseBase([f32; 56]);

impl PhaseBase {
    pub fn new(params: &BaseParams, prev: &PrevFrame) -> PhaseBase {
        let mut phase_base = [0.0; 56];
        let common = (prev.params.fundamental + params.fundamental) *
            SAMPLES as f32 / 2.0;

        (1..57).map(|l| {
            prev.phase_base.get(l) + common * l as f32
        }).collect_slice_checked(&mut phase_base[..]);

        PhaseBase(phase_base)
    }

    pub fn get(&self, l: usize) -> f32 { self.0[l - 1] }
}

impl Default for PhaseBase {
    fn default() -> PhaseBase {
        PhaseBase([0.0; 56])
    }
}

pub struct Phase([f32; 56]);

impl Phase {
    pub fn new(params: &BaseParams, voice: &VoiceDecisions, base: &PhaseBase) -> Phase {
        let mut noise = Noise::new();
        let mut phase = [0.0; 56];

        let trans = params.harmonics as usize / 4;

        (1..trans+1).map(|l| {
            base.get(l)
        }).chain((trans+1..57).map(|l| {
            base.get(l) + voice.unvoiced_count as f32 * noise.next_phase() /
                params.harmonics as f32
        })).collect_slice_checked(&mut phase[..]);

        Phase(phase)
    }

    pub fn get(&self, l: usize) -> f32 { self.0[l - 1] }
}

impl Default for Phase {
    fn default() -> Phase {
        Phase([0.0; 56])
    }
}

pub struct Voiced<'a, 'b, 'c, 'd> {
    prev: &'a PrevFrame,
    phase: &'b Phase,
    enhanced: &'c EnhancedSpectrals,
    voice: &'d VoiceDecisions,
    window: window::Window,
    fundamental: f32,
    end: usize,
    freq_changed: bool,
}

impl<'a, 'b, 'c, 'd> Voiced<'a, 'b, 'c, 'd> {
    pub fn new(params: &BaseParams, prev: &'a PrevFrame, phase: &'b Phase,
               enhanced: &'c EnhancedSpectrals, voice: &'d VoiceDecisions)
        -> Voiced<'a, 'b, 'c, 'd>
    {
        let freq_diff = (params.fundamental - prev.params.fundamental).abs();

        Voiced {
            prev: prev,
            phase: phase,
            enhanced: enhanced,
            voice: voice,
            window: window::synthesis_full(),
            fundamental: params.fundamental,
            end: max(params.harmonics, prev.params.harmonics) as usize + 1,
            freq_changed: freq_diff >= 0.1 * params.fundamental,
        }
    }

    fn get_pair(&self, l: usize, n: isize) -> f32 {
        match (self.voice.is_voiced(l), self.prev.voice.is_voiced(l)) {
            (false, false) => 0.0,
            (false, true) => self.sig_prev(l, n),
            (true, false) => self.sig_cur(l, n),
            (true, true) => if l >= 8 || self.freq_changed {
                self.sig_prev(l, n) + self.sig_cur(l, n)
            } else {
                self.amplitude(l, n) * self.theta(l, n).cos()
            },
        }
    }

    fn sig_cur(&self, l: usize, n: isize) -> f32 {
        self.window.get(n - SAMPLES as isize) * self.enhanced.get(l) * (
            self.fundamental * (n - SAMPLES as isize) as f32 * l as f32 +
                self.phase.get(l)
        ).cos()
    }

    fn sig_prev(&self, l: usize, n: isize) -> f32 {
        self.window.get(n) * self.prev.enhanced.get(l) * (
            self.prev.params.fundamental * n as f32 * l as f32 +
                self.prev.phase.get(l)
        ).cos()
    }

    fn amplitude(&self, l: usize, n: isize) -> f32 {
        self.prev.enhanced.get(l) + n as f32 / SAMPLES as f32 *
            (self.enhanced.get(l) - self.prev.enhanced.get(l))
    }

    fn theta(&self, l: usize, n: isize) -> f32 {
        self.prev.phase.get(l) +
            (self.prev.params.fundamental * l as f32 + self.freq_change(l)) * n as f32 +
            (self.fundamental - self.prev.params.fundamental) *
                l as f32 * (n as f32).powi(2) / (2.0 * SAMPLES as f32)
    }

    fn phase_change(&self, l: usize) -> f32 {
        self.phase.get(l) - self.prev.phase.get(l) - (
            self.prev.params.fundamental + self.fundamental
        ) * l as f32 * SAMPLES as f32 / 2.0
    }

    fn freq_change(&self, l: usize) -> f32 {
        (SAMPLES as f32).recip() * (self.phase_change(l) - 2.0 * PI * (
            (self.phase_change(l) + PI) / (2.0 * PI)
        ).floor())
    }

    pub fn get(&self, n: usize) -> f32 {
        2.0 * (1..self.end).map(|l| {
            self.get_pair(l, n as isize)
        }).fold(0.0, |s, x| s + x)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use params::BaseParams;
    use prev::PrevFrame;
    use descramble::{descramble, Bootstrap};

    #[test]
    fn test_phase_base() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10101110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());
        let prev = PrevFrame::default();

        assert!((p.fundamental - 0.17575344).abs() < 0.000001);
        assert!((prev.params.fundamental - 0.0937765407).abs() < 0.000001);

        let pb = PhaseBase::new(&p, &prev);

        assert!((pb.get(1) - 21.56239846).abs() < 0.0001);
        assert!((pb.get(2) - 43.12479691).abs() < 0.0001);
        assert!((pb.get(3) - 64.68719537).abs() < 0.0001);
        assert!((pb.get(4) - 86.24959382).abs() < 0.0001);
        assert!((pb.get(5) - 107.8119923).abs() < 0.0001);
        assert!((pb.get(6) - 129.3743907).abs() < 0.0001);
        assert!((pb.get(20) - 431.2479691).abs() < 0.0001);
        assert!((pb.get(56) - 1207.494314).abs() < 0.001);
    }
}
<|endoftext|>


<commit_before>use ncurses as nc;
use std::cmp;

use screen_data::ScreenData;

pub struct Window {
    rect: Rect,
    win: nc::WINDOW,
    win_impl: Box<WindowImpl + Send>
}

impl Window {
    pub fn new<WI>(win_impl: WI, r: Rect) -> Window
        where WI: WindowImpl + Send + 'static
    {
        let win = nc::newwin(r.height, r.width, r.y, r.x);
        nc::leaveok(win, true);
        Window {
            rect: r,
            win: win,
            win_impl: Box::new(win_impl)
        }
    }

    pub fn draw(&self, sd: &ScreenData) {
        self.win_impl.draw(self.win, self.rect, sd);
    }

    pub fn clear(&self) {
        nc::wclear(self.win);
    }

    pub fn noutrefresh(&self) {
        nc::wnoutrefresh(self.win);
    }

    pub fn rect(&self) -> Rect {
        self.rect
    }
}

pub trait WindowImpl {
    fn draw(&self, win: nc::WINDOW, r: Rect, sd: &ScreenData);
}

pub struct Gutter;

impl WindowImpl for Gutter {
    fn draw(&self, win: nc::WINDOW, r: Rect, sd: &ScreenData) {
        // TODO: shift
        if sd.items.len() > 0 {
            let i = cmp::min(sd.highlighted_row as i32, r.height);
            nc::mvwaddstr(win, i as i32, 0, ">");
        }
        for row in sd.selected_rows.iter() {
            let i = cmp::min(*row as i32, r.height);
            nc::mvwaddstr(win, i as i32, 1, ">");
        }
    }
}

pub struct MiniBuf;

impl WindowImpl for MiniBuf {
    fn draw(&self, win: nc::WINDOW, _r: Rect, sd: &ScreenData) {
        nc::mvwaddstr(win, 0, 0, &*sd.query_string);
    }
}

impl MiniBuf {
    pub fn set_cursor(win: &Window, cursor_index: i32) {
        let mut beg_y = 0i32;
        let mut beg_x = 0i32;
        nc::getbegyx(win.win, &mut beg_y, &mut beg_x);
        let mut cur_y = 0i32;
        let mut cur_x = 0i32;
        nc::getyx(win.win, &mut cur_y, &mut cur_x);
        let x_offset = 0; // use someday
        let mut scr_cur_y = beg_y + cur_y;
        let mut scr_cur_x = beg_x + x_offset + cursor_index;
        nc::setsyx(&mut scr_cur_y, &mut scr_cur_x);
    }
}

pub struct ListView;

// TODO: shift
impl WindowImpl for ListView {
    fn draw(&self, win: nc::WINDOW, r: Rect, sd: &ScreenData) {
        let num_lines = cmp::min(sd.items.len(), r.height as usize);
        for (y, item) in sd.items.iter().take(num_lines).enumerate() {
            nc::mvwaddstr(win, y as i32, 0, item.as_ref()); // TODO: truncate line
        }
    }
}

pub struct StatusLine;

impl WindowImpl for StatusLine {
    fn draw(&self, win: nc::WINDOW, _r: Rect, sd: &ScreenData) {
        let s = format!("{}/{}", sd.item_list_len, sd.total_lines);
        nc::mvwaddstr(win, 0, 0, &s);
    }
}

#[derive(Clone, Copy)]
pub struct Rect {
    pub height: i32,
    pub width: i32,
    pub y: i32,
    pub x: i32,
}
<commit_msg>Remove unnecessary cmp::min()<commit_after>use ncurses as nc;
use std::cmp;

use screen_data::ScreenData;

pub struct Window {
    rect: Rect,
    win: nc::WINDOW,
    win_impl: Box<WindowImpl + Send>
}

impl Window {
    pub fn new<WI>(win_impl: WI, r: Rect) -> Window
        where WI: WindowImpl + Send + 'static
    {
        let win = nc::newwin(r.height, r.width, r.y, r.x);
        nc::leaveok(win, true);
        Window {
            rect: r,
            win: win,
            win_impl: Box::new(win_impl)
        }
    }

    pub fn draw(&self, sd: &ScreenData) {
        self.win_impl.draw(self.win, self.rect, sd);
    }

    pub fn clear(&self) {
        nc::wclear(self.win);
    }

    pub fn noutrefresh(&self) {
        nc::wnoutrefresh(self.win);
    }

    pub fn rect(&self) -> Rect {
        self.rect
    }
}

pub trait WindowImpl {
    fn draw(&self, win: nc::WINDOW, r: Rect, sd: &ScreenData);
}

pub struct Gutter;

impl WindowImpl for Gutter {
    fn draw(&self, win: nc::WINDOW, _r: Rect, sd: &ScreenData) {
        if sd.items.len() > 0 {
            let y = sd.highlighted_row as i32;
            nc::mvwaddstr(win, y, 0, ">");
        }
        for row in sd.selected_rows.iter() {
            let y = *row as i32;
            nc::mvwaddstr(win, y, 1, ">");
        }
    }
}

pub struct MiniBuf;

impl WindowImpl for MiniBuf {
    fn draw(&self, win: nc::WINDOW, _r: Rect, sd: &ScreenData) {
        nc::mvwaddstr(win, 0, 0, &*sd.query_string);
    }
}

impl MiniBuf {
    pub fn set_cursor(win: &Window, cursor_index: i32) {
        let mut beg_y = 0i32;
        let mut beg_x = 0i32;
        nc::getbegyx(win.win, &mut beg_y, &mut beg_x);
        let mut cur_y = 0i32;
        let mut cur_x = 0i32;
        nc::getyx(win.win, &mut cur_y, &mut cur_x);
        let x_offset = 0; // use someday
        let mut scr_cur_y = beg_y + cur_y;
        let mut scr_cur_x = beg_x + x_offset + cursor_index;
        nc::setsyx(&mut scr_cur_y, &mut scr_cur_x);
    }
}

pub struct ListView;

// TODO: shift
impl WindowImpl for ListView {
    fn draw(&self, win: nc::WINDOW, r: Rect, sd: &ScreenData) {
        let num_lines = cmp::min(sd.items.len(), r.height as usize);
        for (y, item) in sd.items.iter().take(num_lines).enumerate() {
            nc::mvwaddstr(win, y as i32, 0, item.as_ref()); // TODO: truncate line
        }
    }
}

pub struct StatusLine;

impl WindowImpl for StatusLine {
    fn draw(&self, win: nc::WINDOW, _r: Rect, sd: &ScreenData) {
        let s = format!("{}/{}", sd.item_list_len, sd.total_lines);
        nc::mvwaddstr(win, 0, 0, &s);
    }
}

#[derive(Clone, Copy)]
pub struct Rect {
    pub height: i32,
    pub width: i32,
    pub y: i32,
    pub x: i32,
}
<|endoftext|>


<commit_before>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! base class automating dispatcher communication via ZMQ

extern crate zmq;
extern crate rand;
extern crate tempfile;

use zmq::{Error, Message, Context, SNDMORE};
use std::ops::Deref;
use std::thread;
use std::time::Duration;
use std::env;
use std::fs::File;
use std::io::{Read,Write, Seek, SeekFrom};
use std::path::Path;
// use std::str;
use std::process::Command;

/// Generic requirements for CorTeX workers
pub trait Worker {
  /// Core processing method
  fn convert(&self, &Path) -> Option<File>;
  /// Size of chunk for network communication, larger implies less IO, smaller implies less RAM use
  fn message_size(&self) -> usize;
  /// Name of the service, as registered in CorTeX
  fn service(&self) -> String;
  /// URL to the CorTeX dispatcher
  fn source(&self) -> String;
  /// URL to the CorTeX sink
  fn sink(&self) -> String;
  /// main worker loop, works in perpetuity or up to a specified `limit`
  fn start(&self, limit : Option<usize>) -> Result<(), Error> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let mut context_source = Context::new();
    let mut source = context_source.socket(zmq::DEALER).unwrap();
    let identity : String = (0..10).map(|_| rand::random::<u8>() as char).collect();
    source.set_identity(identity.as_bytes()).unwrap();

    assert!(source.connect(&self.source()).is_ok());
    // Connect to a task sink
    let mut context_sink = Context::new();
    let mut sink = context_sink.socket(zmq::PUSH).unwrap();
    assert!(sink.connect(&self.sink()).is_ok());
    // Work in perpetuity
    loop {
      let mut taskid_msg = Message::new().unwrap();
      let mut recv_msg = Message::new().unwrap();

      source.send_str(&self.service(), 0).unwrap();
      source.recv(&mut taskid_msg, 0).unwrap();
      let taskid = taskid_msg.as_str().unwrap();

      // Prepare a File for the input
      let input_filepath = env::temp_dir().to_str().unwrap().to_string() + "/" + taskid ;
      let mut file = File::create(input_filepath.clone()).unwrap();
      loop {
        source.recv(&mut recv_msg, 0).unwrap();

        file.write(recv_msg.deref()).unwrap();
        if !source.get_rcvmore().unwrap() {
          break;
        }
      }

      file.seek(SeekFrom::Start(0)).unwrap();
      let file_opt = self.convert(Path::new(&input_filepath));
      if file_opt.is_some() {
        let mut converted_file = file_opt.unwrap();
        sink.send_str(&self.service(), SNDMORE).unwrap();
        sink.send_str(taskid, SNDMORE).unwrap();
        loop {
          // Stream converted data via zmq
          let message_size = self.message_size();
          let mut data = vec![0; message_size];
          let size = converted_file.read(&mut data).unwrap();
          data.truncate(size);
          if size < message_size {
            // If exhausted, send the last frame
            sink.send(&data,0).unwrap();
            // And terminate
            break;
          } else {
            // If more to go, send the frame and indicate there's more to come
            sink.send(&data,SNDMORE).unwrap();
          }
        }
      }
      else {
        // If there was nothing to do, retry a minute later
        thread::sleep(Duration::new(60,0));
        continue
      }

      work_counter += 1;
      match limit {
        Some(upper_bound) => {
          if work_counter >= upper_bound {
            // Give enough time to complete the Final job.
            thread::sleep(Duration::new(1,0));
            break;
          }
        },
        None => {}
      };
    }
    Ok(())
  }
}
/// An echo worker for testing
pub struct EchoWorker {
  /// the usual
  pub service : String,
  /// the usual
  pub version : f32,
  /// the usual
  pub message_size : usize,
  /// the usual
  pub source : String,
  /// the usual
  pub sink : String
}
impl Default for EchoWorker {
  fn default() -> EchoWorker {
    EchoWorker {
      service: "echo_service".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for EchoWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    Some(File::open(path).unwrap())
  }
}
/// A TeX to HTML conversion worker
pub struct TexToHtmlWorker {
  /// the usual
  pub service : String,
  /// the usual
  pub version : f32,
  /// the usual
  pub message_size : usize,
  /// the usual
  pub source : String,
  /// the usual
  pub sink : String
}
impl Default for TexToHtmlWorker {
  fn default() -> TexToHtmlWorker {
    TexToHtmlWorker {
      service: "tex_to_html".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for TexToHtmlWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    let name = path.file_stem().unwrap().to_str().unwrap();
    let destination_path = env::temp_dir().to_str().unwrap().to_string() + "/" +name+ ".zip";
    // println!("Source {:?}", path);
    Command::new("latexmlc")
      .arg("--whatsin")
      .arg("archive")
      .arg("--whatsout")
      .arg("archive")
      .arg("--format")
      .arg("html5")
      .arg("--pmml")
      .arg("--cmml")
      .arg("--preload")
      .arg("[ids]latexml.sty")
      .arg("--css")
      .arg("http://latexml.mathweb.org/css/external/LaTeXML.css")
      .arg("--nodefaultresources")
      .arg("--inputencoding")
      .arg("iso-8859-1")
      .arg("--timeout")
      .arg("300")
      .arg("--log")
      .arg("cortex.log")
      .arg("--destination")
      .arg(destination_path.clone())
      .arg(path.clone())
      .output()
      .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    // println!("Dest: {:?}", destination_path);
    let file_test = File::open(destination_path.clone());
    match file_test {
      Ok(file) => Some(file),
      Err(_) => None
    }
  }
}
<commit_msg>debug session for cortex testing<commit_after>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! base class automating dispatcher communication via ZMQ

extern crate zmq;
extern crate rand;
extern crate tempfile;

use zmq::{Error, Message, Context, SNDMORE};
use std::ops::Deref;
use std::thread;
use std::time::Duration;
use std::env;
use std::fs::File;
use std::io::{Read,Write, Seek, SeekFrom};
use std::path::Path;
// use std::str;
use std::process::Command;

/// Generic requirements for CorTeX workers
pub trait Worker {
  /// Core processing method
  fn convert(&self, &Path) -> Option<File>;
  /// Size of chunk for network communication, larger implies less IO, smaller implies less RAM use
  fn message_size(&self) -> usize;
  /// Name of the service, as registered in CorTeX
  fn service(&self) -> String;
  /// URL to the CorTeX dispatcher
  fn source(&self) -> String;
  /// URL to the CorTeX sink
  fn sink(&self) -> String;
  /// main worker loop, works in perpetuity or up to a specified `limit`
  fn start(&self, limit : Option<usize>) -> Result<(), Error> {
    let mut work_counter = 0;
    // Connect to a task ventilator
    let mut context_source = Context::new();
    let mut source = context_source.socket(zmq::DEALER).unwrap();
    let identity : String = (0..10).map(|_| rand::random::<u8>() as char).collect();
    source.set_identity(identity.as_bytes()).unwrap();

    assert!(source.connect(&self.source()).is_ok());
    // Connect to a task sink
    let mut context_sink = Context::new();
    let mut sink = context_sink.socket(zmq::PUSH).unwrap();
    assert!(sink.connect(&self.sink()).is_ok());
    // Work in perpetuity
    loop {
      let mut taskid_msg = Message::new().unwrap();
      let mut recv_msg = Message::new().unwrap();

      source.send_str(&self.service(), 0).unwrap();
      source.recv(&mut taskid_msg, 0).unwrap();
      let taskid = taskid_msg.as_str().unwrap();

      // Prepare a File for the input
      let input_filepath = env::temp_dir().to_str().unwrap().to_string() + "/" + taskid ;
      let mut file = File::create(input_filepath.clone()).unwrap();
      loop {
        source.recv(&mut recv_msg, 0).unwrap();

        file.write(recv_msg.deref()).unwrap();
        if !source.get_rcvmore().unwrap() {
          break;
        }
      }

      file.seek(SeekFrom::Start(0)).unwrap();
      let file_opt = self.convert(Path::new(&input_filepath));
      if file_opt.is_some() {
        let mut converted_file = file_opt.unwrap();
        sink.send_str(&self.service(), SNDMORE).unwrap();
        sink.send_str(taskid, SNDMORE).unwrap();
        loop {
          // Stream converted data via zmq
          let message_size = self.message_size();
          let mut data = vec![0; message_size];
          let size = converted_file.read(&mut data).unwrap();
          data.truncate(size);
          if size < message_size {
            // If exhausted, send the last frame
            sink.send(&data,0).unwrap();
            // And terminate
            break;
          } else {
            // If more to go, send the frame and indicate there's more to come
            sink.send(&data,SNDMORE).unwrap();
          }
        }
      }
      else {
        // If there was nothing to do, retry a minute later
        thread::sleep(Duration::new(60,0));
        continue
      }

      work_counter += 1;
      match limit {
        Some(upper_bound) => {
          if work_counter >= upper_bound {
            // Give enough time to complete the Final job.
            thread::sleep(Duration::new(1,0));
            break;
          }
        },
        None => {}
      };
    }
    Ok(())
  }
}
/// An echo worker for testing
pub struct EchoWorker {
  /// the usual
  pub service : String,
  /// the usual
  pub version : f32,
  /// the usual
  pub message_size : usize,
  /// the usual
  pub source : String,
  /// the usual
  pub sink : String
}
impl Default for EchoWorker {
  fn default() -> EchoWorker {
    EchoWorker {
      service: "echo_service".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for EchoWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    Some(File::open(path).unwrap())
  }
}
/// A TeX to HTML conversion worker
pub struct TexToHtmlWorker {
  /// the usual
  pub service : String,
  /// the usual
  pub version : f32,
  /// the usual
  pub message_size : usize,
  /// the usual
  pub source : String,
  /// the usual
  pub sink : String
}
impl Default for TexToHtmlWorker {
  fn default() -> TexToHtmlWorker {
    TexToHtmlWorker {
      service: "tex_to_html".to_string(),
      version: 0.1,
      message_size: 100000,
      source: "tcp://localhost:5555".to_string(),
      sink: "tcp://localhost:5556".to_string()
    }
  }
}
impl Worker for TexToHtmlWorker {
  fn service(&self) -> String {self.service.clone()}
  fn source(&self) -> String {self.source.clone()}
  fn sink(&self) -> String {self.sink.clone()}
  fn message_size(&self) -> usize {self.message_size.clone()}

  fn convert(&self, path : &Path) -> Option<File> {
    let name = path.file_stem().unwrap().to_str().unwrap();
    let destination_path = env::temp_dir().to_str().unwrap().to_string() + "/" +name+ ".zip";
    println!("Source {:?}", path);
    Command::new("latexmlc")
      .arg("--whatsin")
      .arg("archive")
      .arg("--whatsout")
      .arg("archive")
      .arg("--format")
      .arg("html5")
      .arg("--pmml")
      .arg("--cmml")
      .arg("--mathtex")
      .arg("--preload")
      .arg("[ids]latexml.sty")
      .arg("--nodefaultresources")
      .arg("--inputencoding")
      .arg("iso-8859-1")
      .arg("--timeout")
      .arg("300")
      .arg("--log")
      .arg("cortex.log")
      .arg("--destination")
      .arg(destination_path.clone())
      .arg(path.clone())
      .output()
      .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    println!("Dest: {:?}", destination_path);
    let file_test = File::open(destination_path.clone());
    match file_test {
      Ok(file) => Some(file),
      Err(_) => None
    }
  }
}
<|endoftext|>


<commit_before>//! This module allows you to write to a CDB.
use helpers::{hash, pack};
use reader::Reader;
use std::io::{Read, Seek, SeekFrom, Write};
use types::Result;

/// Allows you to create a (or append to) CDB.
///
/// #Example
///
/// ```
/// # use galvanize::Result;
/// use galvanize::Writer;
/// use std::fs::File;
///
/// # // Doing this to get around the fact that you can't have `try!` in `main`.
/// # fn main() {
/// #     let _ = do_try();
/// # }
/// #
/// # fn do_try() -> Result<()> {
/// # let filename = "writer_example.cdb";
/// #
/// let mut f = File::create(filename)?;
/// let mut cdb_writer = Writer::new(&mut f)?;
/// let key = "key".as_bytes();
/// let value = "value".as_bytes();
/// cdb_writer.put(key, value)?;
///
/// // Write out the hash table from the `Writer` and transform into a `Reader`
/// let mut cdb_reader = cdb_writer.as_reader()?;
/// let stored_vals = cdb_reader.get(key);
/// assert_eq!(stored_vals.len(), 1);
/// assert_eq!(&stored_vals[0][..], &value[..]);  // "value".as_bytes()
/// #
/// #     Ok(())
/// # }
/// ```
pub struct Writer<'a, F: Write + Read + Seek + 'a> {
    /// Opened file to write values into.
    file: &'a mut F,
    /// Working hash table for the contents of the CDB.
    index: Vec<Vec<(u32, u32)>>,
}

impl<'a, F: Write + Read + Seek + 'a> Writer<'a, F> {
    /// Creates a new `Reader` consuming the provided `file`.
    ///
    /// The `file` must allow writes to be performed.
    pub fn new(file: &'a mut F) -> Result<Writer<'a, F>> {
        file.seek(SeekFrom::Start(0))?;
        file.write(&[0; 2048])?;

        Self::new_with_index(file, vec![Vec::new(); 256])
    }

    /// Used by `Reader::as_writer` method, to prepopulate the index from the
    /// underlying `file`.
    pub fn new_with_index(file: &'a mut F, index: Vec<Vec<(u32, u32)>>) -> Result<Writer<'a, F>> {
        Ok(Writer {
            file: file,
            index: index,
        })
    }

    /// Write `value` for `key` into this CDB.
    pub fn put(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
        let pos = self.file.seek(SeekFrom::Current(0))? as u32;
        self.file.write(&pack(key.len() as u32))?;
        self.file.write(&pack(value.len() as u32))?;

        self.file.write(key)?;
        self.file.write(value)?;

        let h = hash(key) & 0xffffffff;
        self.index[(h & 0xff) as usize].push((h, pos));
        Ok(())
    }

    /// Write out the hash table to the `file` footer.
    fn finalize(&mut self) {
        let mut index: Vec<(u32, u32)> = Vec::new();

        &self.file.seek(SeekFrom::End(0));
        for tbl in &self.index {
            let length = (tbl.len() << 1) as u32;
            let mut ordered: Vec<(u32, u32)> = vec!((0, 0); length as usize);
            for &pair in tbl {
                let where_ = (pair.0 >> 8) % length;
                for i in (where_..length).chain(0..where_) {
                    if ordered[i as usize].0 == 0 {
                        ordered[i as usize] = pair;
                        break;
                    }
                }
            }
            index.push((self.file.seek(SeekFrom::End(0)).unwrap() as u32, length));
            for pair in ordered {
                &self.file.write(&pack(pair.0));
                &self.file.write(&pack(pair.1));
            }
        }

        &self.file.seek(SeekFrom::Start(0));
        for pair in index {
            &self.file.write(&pack(pair.0));
            &self.file.write(&pack(pair.1));
        }
    }

    /// Transform this `Writer` into a `Reader` using the same underlying
    /// `file`.
    ///
    /// The `Writer` will flush the hash table to the underlying `file`.
    pub fn as_reader(mut self) -> Result<Reader<'a, F>> {
        {
            let s = &mut self;
            s.finalize();
        }
        Reader::new(self.file)
    }
}

impl<'a, F: Write + Read + Seek + 'a> Drop for Writer<'a, F> {
    /// Write out the hash table footer for this CDB.
    fn drop(&mut self) {
        self.finalize();
    }
}
<commit_msg>Fix old unsoundness issue<commit_after>//! This module allows you to write to a CDB.
use helpers::{hash, pack};
use reader::Reader;
use std::io::{Read, Seek, SeekFrom, Write};
use types::Result;

/// Allows you to create a (or append to) CDB.
///
/// #Example
///
/// ```
/// # use galvanize::Result;
/// use galvanize::Writer;
/// use std::fs::File;
///
/// # // Doing this to get around the fact that you can't have `try!` in `main`.
/// # fn main() {
/// #     let _ = do_try();
/// # }
/// #
/// # fn do_try() -> Result<()> {
/// # let filename = "writer_example.cdb";
/// #
/// let mut f = File::create(filename)?;
/// let mut cdb_writer = Writer::new(&mut f)?;
/// let key = "key".as_bytes();
/// let value = "value".as_bytes();
/// cdb_writer.put(key, value)?;
///
/// // Write out the hash table from the `Writer` and transform into a `Reader`
/// let mut cdb_reader = cdb_writer.as_reader()?;
/// let stored_vals = cdb_reader.get(key);
/// assert_eq!(stored_vals.len(), 1);
/// assert_eq!(&stored_vals[0][..], &value[..]);  // "value".as_bytes()
/// #
/// #     Ok(())
/// # }
/// ```
pub struct Writer<'a, F: Write + Read + Seek + 'a> {
    /// Opened file to write values into.
    file: Option<&'a mut F>,
    /// Working hash table for the contents of the CDB.
    index: Vec<Vec<(u32, u32)>>,
}

impl<'a, F: Write + Read + Seek + 'a> Writer<'a, F> {
    /// Creates a new `Reader` consuming the provided `file`.
    ///
    /// The `file` must allow writes to be performed.
    pub fn new(file: &'a mut F) -> Result<Writer<'a, F>> {
        file.seek(SeekFrom::Start(0))?;
        file.write(&[0; 2048])?;

        Self::new_with_index(file, vec![Vec::new(); 256])
    }

    /// Used by `Reader::as_writer` method, to prepopulate the index from the
    /// underlying `file`.
    pub fn new_with_index(file: &'a mut F, index: Vec<Vec<(u32, u32)>>) -> Result<Writer<'a, F>> {
        Ok(Writer {
            file: Some(file),
            index: index,
        })
    }

    /// Write `value` for `key` into this CDB.
    pub fn put(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
        let file = self.file.as_mut().unwrap();
        let pos = file.seek(SeekFrom::Current(0))? as u32;
        file.write(&pack(key.len() as u32))?;
        file.write(&pack(value.len() as u32))?;

        file.write(key)?;
        file.write(value)?;

        let h = hash(key) & 0xffffffff;
        self.index[(h & 0xff) as usize].push((h, pos));
        Ok(())
    }

    /// Write out the hash table to the `file` footer.
    fn finalize(&mut self) {
        let mut index: Vec<(u32, u32)> = Vec::new();

        let file = if let Some(file) = self.file.as_mut() {
            file.seek(SeekFrom::End(0)).unwrap();
            file
        } else {
            return;
        };
        for tbl in &self.index {
            let length = (tbl.len() << 1) as u32;
            let mut ordered: Vec<(u32, u32)> = vec!((0, 0); length as usize);
            for &pair in tbl {
                let where_ = (pair.0 >> 8) % length;
                for i in (where_..length).chain(0..where_) {
                    if ordered[i as usize].0 == 0 {
                        ordered[i as usize] = pair;
                        break;
                    }
                }
            }
            index.push((*file.seek(SeekFrom::End(0)).as_mut().unwrap() as u32, length));
            for pair in ordered {
                file.write(&pack(pair.0)).unwrap();
                file.write(&pack(pair.1)).unwrap();
            }
        }

        file.seek(SeekFrom::Start(0)).unwrap();
        for pair in index {
            file.write(&pack(pair.0)).unwrap();
            file.write(&pack(pair.1)).unwrap();
        }
    }

    /// Transform this `Writer` into a `Reader` using the same underlying
    /// `file`.
    ///
    /// The `Writer` will flush the hash table to the underlying `file`.
    pub fn as_reader(mut self) -> Result<Reader<'a, F>> {
        {
            let s = &mut self;
            s.finalize();
        }
        let file = self.file.take().unwrap();
        Reader::new(file)
    }
}

impl<'a, F: Write + Read + Seek + 'a> Drop for Writer<'a, F> {
    /// Write out the hash table footer for this CDB.
    fn drop(&mut self) {
        self.finalize();
    }
}
<|endoftext|>


<commit_before>#[macro_escape];

use std::io::BufferedWriter;
use std::io::{File, Writer};
use std::str::Chars;
use std::vec_ng::Vec;

struct ParseBranch {
    matches: Vec<u8>,
    result: Option<~str>,
    children: Vec<ParseBranch>,
}

impl ParseBranch {
    fn new() -> ParseBranch {
        ParseBranch {
            matches: Vec::new(),
            result: None,
            children: Vec::new(),
        }
    }
}

pub fn branchify(options: &[(&str, &str)], case_sensitive: bool) -> Vec<ParseBranch> {
    let mut root = ParseBranch::new();

    fn go_down_moses(branch: &mut ParseBranch, mut chariter: Chars, result: &str, case_sensitive: bool) {
        match chariter.next() {
            Some(c) => {
                let first_case = if case_sensitive { c as u8 } else { c.to_ascii().to_upper().to_byte() };
                for next_branch in branch.children.mut_iter() {
                    if next_branch.matches.as_slice()[0] == first_case {
                        go_down_moses(next_branch, chariter, result, case_sensitive);
                        return;
                    }
                }
                let mut subbranch = ParseBranch::new();
                subbranch.matches.push(first_case);
                if !case_sensitive {
                    let second_case = c.to_ascii().to_lower().to_byte();
                    if first_case != second_case {
                        subbranch.matches.push(second_case);
                    }
                }
                branch.children.push(subbranch);
                let index = branch.children.len() -1;
                go_down_moses(&mut branch.children.as_mut_slice()[index], chariter, result, case_sensitive);
            },
            None => {
                assert!(branch.result.is_none());
                branch.result = Some(result.to_owned());
            },
        }
    };

    for &(key, result) in options.iter() {
        go_down_moses(&mut root, key.chars(), result, case_sensitive);
    }

    root.children
}

macro_rules! branchify(
    (case sensitive, $($key:expr => $value:ident),*) => (
        ::branchify::branchify([$(($key, stringify!($value))),*], true)
    );
    (case insensitive, $($key:expr => $value:ident),*) => (
        branchify([$(($key, stringify!($value))),*], false)
    );
)

/// Prints the contents to stdout.
///
/// :param branches: the branches to search through
/// :param indent: the level of indentation (each level representing four leading spaces)
/// :param read_call: the function call to read a byte
/// :param end: the byte which marks the end of the sequence
/// :param max_len: the maximum length a value may be before giving up and returning ``None``
/// :param valid: the function call to if a byte ``b`` is valid
/// :param unknown: the expression to call for an unknown value; in this string, ``{}`` will be
///         replaced with an expression (literal or non-literal) evaluating to a ``~str`` (it is
///         ``{}`` only, not arbitrary format strings)
pub fn generate_branchified_method(
        writer: &mut BufferedWriter<File>,
        branches: &[ParseBranch],
        indent: uint,
        read_call: &str,
        end: &str,
        max_len: &str,
        valid: &str,
        unknown: &str) {

    // Write Formatted
    macro_rules! wf(($($x:tt)*) => ({
        let indentstr = " ".repeat(indent * 4);
        let s = format!($($x)*);
        writer.write(indentstr.as_bytes());
        writer.write(s.as_bytes());
        writer.write(bytes!("\n"));
    }))

    fn r(writer: &mut BufferedWriter<File>, branch: &ParseBranch, prefix: &str, indent: uint, read_call: &str,
            end: &str, max_len: &str, valid: &str, unknown: &str) {
        for &c in branch.matches.iter() {
            let next_prefix = format!("{}{}", prefix, c as char);
            wf!("Some(b) if b == '{}' as u8 => match {} \\{", c as char, read_call);
            for b in branch.children.iter() {
                r(writer, b, next_prefix, indent + 1, read_call, end, max_len, valid, unknown);
            }
            match branch.result {
                Some(ref result) => wf!("    Some(b) if b == SP => return Some({}),", *result),
                None => wf!("    Some(b) if b == SP => return Some({}),",
                                unknown.replace("{}", format!("~\"{}\"", next_prefix))),
            }
            wf!("    Some(b) if {} => (\"{}\", b),", valid, next_prefix);
            wf!("    _ => return None,");
            wf!("\\},");
        }
    }
    wf!("let (s, next_byte) = match {} \\{", read_call);
    for b in branches.iter() {
        r(writer, b, "", indent + 1, read_call, end, max_len, valid, unknown);
    }
    wf!("    Some(b) if {} => (\"\", b),", valid);
    wf!("    _ => return None,");
    wf!("\\};");
    wf!("// OK, that didn't pan out. Let's read the rest and see what we get.");
    wf!("let mut s = s.to_owned();");
    wf!("s.push_char(next_byte as char);");
    wf!("loop \\{");
    wf!("    match {} \\{", read_call);
    wf!("        Some(b) if b == {} => return Some({}),", end, unknown.replace("{}", "s"));
    wf!("        Some(b) if {} => \\{", valid);
    wf!("            if s.len() == {} \\{", max_len);
    wf!("                // Too long; bad request");
    wf!("                return None;");
    wf!("            \\}");
    wf!("            s.push_char(b as char);");
    wf!("        \\},");
    wf!("        _ => return None,");
    wf!("    \\}");
    wf!("\\}");
}
<commit_msg>Consume result in `wf!` macro, considering write errors to be fatal.<commit_after>#[macro_escape];

use std::io::BufferedWriter;
use std::io::{File, Writer};
use std::str::Chars;
use std::vec_ng::Vec;

struct ParseBranch {
    matches: Vec<u8>,
    result: Option<~str>,
    children: Vec<ParseBranch>,
}

impl ParseBranch {
    fn new() -> ParseBranch {
        ParseBranch {
            matches: Vec::new(),
            result: None,
            children: Vec::new(),
        }
    }
}

pub fn branchify(options: &[(&str, &str)], case_sensitive: bool) -> Vec<ParseBranch> {
    let mut root = ParseBranch::new();

    fn go_down_moses(branch: &mut ParseBranch, mut chariter: Chars, result: &str, case_sensitive: bool) {
        match chariter.next() {
            Some(c) => {
                let first_case = if case_sensitive { c as u8 } else { c.to_ascii().to_upper().to_byte() };
                for next_branch in branch.children.mut_iter() {
                    if next_branch.matches.as_slice()[0] == first_case {
                        go_down_moses(next_branch, chariter, result, case_sensitive);
                        return;
                    }
                }
                let mut subbranch = ParseBranch::new();
                subbranch.matches.push(first_case);
                if !case_sensitive {
                    let second_case = c.to_ascii().to_lower().to_byte();
                    if first_case != second_case {
                        subbranch.matches.push(second_case);
                    }
                }
                branch.children.push(subbranch);
                let index = branch.children.len() -1;
                go_down_moses(&mut branch.children.as_mut_slice()[index], chariter, result, case_sensitive);
            },
            None => {
                assert!(branch.result.is_none());
                branch.result = Some(result.to_owned());
            },
        }
    };

    for &(key, result) in options.iter() {
        go_down_moses(&mut root, key.chars(), result, case_sensitive);
    }

    root.children
}

macro_rules! branchify(
    (case sensitive, $($key:expr => $value:ident),*) => (
        ::branchify::branchify([$(($key, stringify!($value))),*], true)
    );
    (case insensitive, $($key:expr => $value:ident),*) => (
        branchify([$(($key, stringify!($value))),*], false)
    );
)

/// Prints the contents to stdout.
///
/// :param branches: the branches to search through
/// :param indent: the level of indentation (each level representing four leading spaces)
/// :param read_call: the function call to read a byte
/// :param end: the byte which marks the end of the sequence
/// :param max_len: the maximum length a value may be before giving up and returning ``None``
/// :param valid: the function call to if a byte ``b`` is valid
/// :param unknown: the expression to call for an unknown value; in this string, ``{}`` will be
///         replaced with an expression (literal or non-literal) evaluating to a ``~str`` (it is
///         ``{}`` only, not arbitrary format strings)
pub fn generate_branchified_method(
        writer: &mut BufferedWriter<File>,
        branches: &[ParseBranch],
        indent: uint,
        read_call: &str,
        end: &str,
        max_len: &str,
        valid: &str,
        unknown: &str) {

    // Write Formatted
    macro_rules! wf(($($x:tt)*) => ({
        let indentstr = " ".repeat(indent * 4);
        let s = format!($($x)*);
        let result = writer.write(indentstr.as_bytes())
        .and(writer.write(s.as_bytes()))
        .and(writer.write(bytes!("\n")));

        match result {
            Ok(_)  => {},
            Err(e) => fail!("write error: {:s}", e.desc),
        }
    }))

    fn r(writer: &mut BufferedWriter<File>, branch: &ParseBranch, prefix: &str, indent: uint, read_call: &str,
            end: &str, max_len: &str, valid: &str, unknown: &str) {
        for &c in branch.matches.iter() {
            let next_prefix = format!("{}{}", prefix, c as char);
            wf!("Some(b) if b == '{}' as u8 => match {} \\{", c as char, read_call);
            for b in branch.children.iter() {
                r(writer, b, next_prefix, indent + 1, read_call, end, max_len, valid, unknown);
            }
            match branch.result {
                Some(ref result) => wf!("    Some(b) if b == SP => return Some({}),", *result),
                None => wf!("    Some(b) if b == SP => return Some({}),",
                                unknown.replace("{}", format!("~\"{}\"", next_prefix))),
            }
            wf!("    Some(b) if {} => (\"{}\", b),", valid, next_prefix);
            wf!("    _ => return None,");
            wf!("\\},");
        }
    }
    wf!("let (s, next_byte) = match {} \\{", read_call);
    for b in branches.iter() {
        r(writer, b, "", indent + 1, read_call, end, max_len, valid, unknown);
    }
    wf!("    Some(b) if {} => (\"\", b),", valid);
    wf!("    _ => return None,");
    wf!("\\};");
    wf!("// OK, that didn't pan out. Let's read the rest and see what we get.");
    wf!("let mut s = s.to_owned();");
    wf!("s.push_char(next_byte as char);");
    wf!("loop \\{");
    wf!("    match {} \\{", read_call);
    wf!("        Some(b) if b == {} => return Some({}),", end, unknown.replace("{}", "s"));
    wf!("        Some(b) if {} => \\{", valid);
    wf!("            if s.len() == {} \\{", max_len);
    wf!("                // Too long; bad request");
    wf!("                return None;");
    wf!("            \\}");
    wf!("            s.push_char(b as char);");
    wf!("        \\},");
    wf!("        _ => return None,");
    wf!("    \\}");
    wf!("\\}");
}
<|endoftext|>