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

use base::CGFloat;
use color_space::{CGColorSpace, CGColorSpaceRef};
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use libc::{c_void, c_int, size_t};
use std::mem;
use std::ptr;
use std::slice;
use geometry::CGRect;
use image::{CGImage, CGImageRef};

#[repr(C)]
pub enum CGTextDrawingMode {
    CGTextFill,
    CGTextStroke,
    CGTextFillStroke,
    CGTextInvisible,
    CGTextFillClip,
    CGTextStrokeClip,
    CGTextClip
}

#[repr(C)]
pub struct __CGContext;

pub type CGContextRef = *const __CGContext;

pub struct CGContext {
    obj: CGContextRef,
}

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

impl Clone for CGContext {
    fn clone(&self) -> CGContext {
        unsafe {
            TCFType::wrap_under_get_rule(self.as_concrete_TypeRef())
        }
    }
}

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

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

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

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

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

impl CGContext {
    pub fn create_bitmap_context(data: Option<*mut c_void>,
                                 width: size_t,
                                 height: size_t,
                                 bits_per_component: size_t,
                                 bytes_per_row: size_t,
                                 space: &CGColorSpace,
                                 bitmap_info: u32)
                                 -> CGContext {
        unsafe {
            let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()),
                                               width,
                                               height,
                                               bits_per_component,
                                               bytes_per_row,
                                               space.as_concrete_TypeRef(),
                                               bitmap_info);
            TCFType::wrap_under_create_rule(result)
        }
    }

    pub fn data(&mut self) -> &mut [u8] {
        unsafe {
            slice::from_raw_parts_mut(
                    CGBitmapContextGetData(self.as_concrete_TypeRef()) as *mut u8,
                    (self.height() * self.bytes_per_row()) as usize)
        }
    }

    pub fn width(&self) -> size_t {
        unsafe {
            CGBitmapContextGetWidth(self.as_concrete_TypeRef())
        }
    }

    pub fn height(&self) -> size_t {
        unsafe {
            CGBitmapContextGetHeight(self.as_concrete_TypeRef())
        }
    }

    pub fn bytes_per_row(&self) -> size_t {
        unsafe {
            CGBitmapContextGetBytesPerRow(self.as_concrete_TypeRef())
        }
    }

    pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        unsafe {
            CGContextSetRGBFillColor(self.as_concrete_TypeRef(), red, green, blue, alpha)
        }
    }

    pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) {
        unsafe {
            CGContextSetAllowsFontSmoothing(self.as_concrete_TypeRef(), allows_font_smoothing)
        }
    }

    fn set_font_smoothing_style(&self, style: i32) {
        unsafe {
            CGContextSetFontSmoothingStyle(self.as_concrete_TypeRef(), style as _);
        }
    }

    pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) {
        unsafe {
            CGContextSetShouldSmoothFonts(self.as_concrete_TypeRef(), should_smooth_fonts)
        }
    }

    pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) {
        unsafe {
            CGContextSetAllowsAntialiasing(self.as_concrete_TypeRef(), allows_antialiasing)
        }
    }

    pub fn set_should_antialias(&self, should_antialias: bool) {
        unsafe {
            CGContextSetShouldAntialias(self.as_concrete_TypeRef(), should_antialias)
        }
    }

    pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) {
        unsafe {
            CGContextSetAllowsFontSubpixelQuantization(self.as_concrete_TypeRef(), allows_font_subpixel_quantization)
        }
    }

    pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) {
        unsafe {
            CGContextSetShouldSubpixelQuantizeFonts(self.as_concrete_TypeRef(), should_subpixel_quantize_fonts)
        }
    }

    pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) {
        unsafe {
            CGContextSetAllowsFontSubpixelPositioning(self.as_concrete_TypeRef(), allows_font_subpixel_positioning)
        }
    }

    pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) {
        unsafe {
            CGContextSetShouldSubpixelPositionFonts(self.as_concrete_TypeRef(), should_subpixel_position_fonts)
        }
    }

    pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) {
        unsafe {
            CGContextSetTextDrawingMode(self.as_concrete_TypeRef(), mode)
        }
    }

    pub fn fill_rect(&self, rect: CGRect) {
        unsafe {
            CGContextFillRect(self.as_concrete_TypeRef(), rect)
        }
    }

    pub fn draw_image(&self, rect: CGRect, image: &CGImage) {
        unsafe {
            CGContextDrawImage(self.as_concrete_TypeRef(), rect, image.as_concrete_TypeRef());
        }
    }

    pub fn create_image(&self) -> Option<CGImage> {
        let image = unsafe { CGBitmapContextCreateImage(self.as_concrete_TypeRef()) };
        if image != ptr::null() {
            Some(unsafe { CGImage::wrap_under_create_rule(image) })
        } else {
            None
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    fn CGBitmapContextCreate(data: *mut c_void,
                             width: size_t,
                             height: size_t,
                             bitsPerComponent: size_t,
                             bytesPerRow: size_t,
                             space: CGColorSpaceRef,
                             bitmapInfo: u32)
                             -> CGContextRef;
    fn CGBitmapContextGetData(context: CGContextRef) -> *mut c_void;
    fn CGBitmapContextGetWidth(context: CGContextRef) -> size_t;
    fn CGBitmapContextGetHeight(context: CGContextRef) -> size_t;
    fn CGBitmapContextGetBytesPerRow(context: CGContextRef) -> size_t;
    fn CGBitmapContextCreateImage(context: CGContextRef) -> CGImageRef;
    fn CGContextGetTypeID() -> CFTypeID;
    fn CGContextSetAllowsFontSmoothing(c: CGContextRef, allowsFontSmoothing: bool);
    fn CGContextSetShouldSmoothFonts(c: CGContextRef, shouldSmoothFonts: bool);
    fn CGContextSetFontSmoothingStyle(c: CGContextRef, style: c_int);
    fn CGContextSetAllowsAntialiasing(c: CGContextRef, allowsAntialiasing: bool);
    fn CGContextSetShouldAntialias(c: CGContextRef, shouldAntialias: bool);
    fn CGContextSetAllowsFontSubpixelQuantization(c: CGContextRef,
                                                  allowsFontSubpixelQuantization: bool);
    fn CGContextSetShouldSubpixelQuantizeFonts(c: CGContextRef,
                                               shouldSubpixelQuantizeFonts: bool);
    fn CGContextSetAllowsFontSubpixelPositioning(c: CGContextRef,
                                                 allowsFontSubpixelPositioning: bool);
    fn CGContextSetShouldSubpixelPositionFonts(c: CGContextRef,
                                               shouldSubpixelPositionFonts: bool);
    fn CGContextSetTextDrawingMode(c: CGContextRef, mode: CGTextDrawingMode);
    fn CGContextSetRGBFillColor(context: CGContextRef,
                                red: CGFloat,
                                green: CGFloat,
                                blue: CGFloat,
                                alpha: CGFloat);
    fn CGContextFillRect(context: CGContextRef,
                         rect: CGRect);
    fn CGContextDrawImage(c: CGContextRef, rect: CGRect, image: CGImageRef);
}

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

use base::CGFloat;
use color_space::{CGColorSpace, CGColorSpaceRef};
use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use libc::{c_void, c_int, size_t};
use std::mem;
use std::ptr;
use std::slice;
use geometry::CGRect;
use image::{CGImage, CGImageRef};

#[repr(C)]
pub enum CGTextDrawingMode {
    CGTextFill,
    CGTextStroke,
    CGTextFillStroke,
    CGTextInvisible,
    CGTextFillClip,
    CGTextStrokeClip,
    CGTextClip
}

#[repr(C)]
pub struct __CGContext;

pub type CGContextRef = *const __CGContext;

pub struct CGContext {
    obj: CGContextRef,
}

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

impl Clone for CGContext {
    fn clone(&self) -> CGContext {
        unsafe {
            TCFType::wrap_under_get_rule(self.as_concrete_TypeRef())
        }
    }
}

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

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

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

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

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

impl CGContext {
    pub fn create_bitmap_context(data: Option<*mut c_void>,
                                 width: size_t,
                                 height: size_t,
                                 bits_per_component: size_t,
                                 bytes_per_row: size_t,
                                 space: &CGColorSpace,
                                 bitmap_info: u32)
                                 -> CGContext {
        unsafe {
            let result = CGBitmapContextCreate(data.unwrap_or(ptr::null_mut()),
                                               width,
                                               height,
                                               bits_per_component,
                                               bytes_per_row,
                                               space.as_concrete_TypeRef(),
                                               bitmap_info);
            TCFType::wrap_under_create_rule(result)
        }
    }

    pub fn data(&mut self) -> &mut [u8] {
        unsafe {
            slice::from_raw_parts_mut(
                    CGBitmapContextGetData(self.as_concrete_TypeRef()) as *mut u8,
                    (self.height() * self.bytes_per_row()) as usize)
        }
    }

    pub fn width(&self) -> size_t {
        unsafe {
            CGBitmapContextGetWidth(self.as_concrete_TypeRef())
        }
    }

    pub fn height(&self) -> size_t {
        unsafe {
            CGBitmapContextGetHeight(self.as_concrete_TypeRef())
        }
    }

    pub fn bytes_per_row(&self) -> size_t {
        unsafe {
            CGBitmapContextGetBytesPerRow(self.as_concrete_TypeRef())
        }
    }

    pub fn set_rgb_fill_color(&self, red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        unsafe {
            CGContextSetRGBFillColor(self.as_concrete_TypeRef(), red, green, blue, alpha)
        }
    }

    pub fn set_allows_font_smoothing(&self, allows_font_smoothing: bool) {
        unsafe {
            CGContextSetAllowsFontSmoothing(self.as_concrete_TypeRef(), allows_font_smoothing)
        }
    }

    pub fn set_font_smoothing_style(&self, style: i32) {
        unsafe {
            CGContextSetFontSmoothingStyle(self.as_concrete_TypeRef(), style as _);
        }
    }

    pub fn set_should_smooth_fonts(&self, should_smooth_fonts: bool) {
        unsafe {
            CGContextSetShouldSmoothFonts(self.as_concrete_TypeRef(), should_smooth_fonts)
        }
    }

    pub fn set_allows_antialiasing(&self, allows_antialiasing: bool) {
        unsafe {
            CGContextSetAllowsAntialiasing(self.as_concrete_TypeRef(), allows_antialiasing)
        }
    }

    pub fn set_should_antialias(&self, should_antialias: bool) {
        unsafe {
            CGContextSetShouldAntialias(self.as_concrete_TypeRef(), should_antialias)
        }
    }

    pub fn set_allows_font_subpixel_quantization(&self, allows_font_subpixel_quantization: bool) {
        unsafe {
            CGContextSetAllowsFontSubpixelQuantization(self.as_concrete_TypeRef(), allows_font_subpixel_quantization)
        }
    }

    pub fn set_should_subpixel_quantize_fonts(&self, should_subpixel_quantize_fonts: bool) {
        unsafe {
            CGContextSetShouldSubpixelQuantizeFonts(self.as_concrete_TypeRef(), should_subpixel_quantize_fonts)
        }
    }

    pub fn set_allows_font_subpixel_positioning(&self, allows_font_subpixel_positioning: bool) {
        unsafe {
            CGContextSetAllowsFontSubpixelPositioning(self.as_concrete_TypeRef(), allows_font_subpixel_positioning)
        }
    }

    pub fn set_should_subpixel_position_fonts(&self, should_subpixel_position_fonts: bool) {
        unsafe {
            CGContextSetShouldSubpixelPositionFonts(self.as_concrete_TypeRef(), should_subpixel_position_fonts)
        }
    }

    pub fn set_text_drawing_mode(&self, mode: CGTextDrawingMode) {
        unsafe {
            CGContextSetTextDrawingMode(self.as_concrete_TypeRef(), mode)
        }
    }

    pub fn fill_rect(&self, rect: CGRect) {
        unsafe {
            CGContextFillRect(self.as_concrete_TypeRef(), rect)
        }
    }

    pub fn draw_image(&self, rect: CGRect, image: &CGImage) {
        unsafe {
            CGContextDrawImage(self.as_concrete_TypeRef(), rect, image.as_concrete_TypeRef());
        }
    }

    pub fn create_image(&self) -> Option<CGImage> {
        let image = unsafe { CGBitmapContextCreateImage(self.as_concrete_TypeRef()) };
        if image != ptr::null() {
            Some(unsafe { CGImage::wrap_under_create_rule(image) })
        } else {
            None
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {
    fn CGBitmapContextCreate(data: *mut c_void,
                             width: size_t,
                             height: size_t,
                             bitsPerComponent: size_t,
                             bytesPerRow: size_t,
                             space: CGColorSpaceRef,
                             bitmapInfo: u32)
                             -> CGContextRef;
    fn CGBitmapContextGetData(context: CGContextRef) -> *mut c_void;
    fn CGBitmapContextGetWidth(context: CGContextRef) -> size_t;
    fn CGBitmapContextGetHeight(context: CGContextRef) -> size_t;
    fn CGBitmapContextGetBytesPerRow(context: CGContextRef) -> size_t;
    fn CGBitmapContextCreateImage(context: CGContextRef) -> CGImageRef;
    fn CGContextGetTypeID() -> CFTypeID;
    fn CGContextSetAllowsFontSmoothing(c: CGContextRef, allowsFontSmoothing: bool);
    fn CGContextSetShouldSmoothFonts(c: CGContextRef, shouldSmoothFonts: bool);
    fn CGContextSetFontSmoothingStyle(c: CGContextRef, style: c_int);
    fn CGContextSetAllowsAntialiasing(c: CGContextRef, allowsAntialiasing: bool);
    fn CGContextSetShouldAntialias(c: CGContextRef, shouldAntialias: bool);
    fn CGContextSetAllowsFontSubpixelQuantization(c: CGContextRef,
                                                  allowsFontSubpixelQuantization: bool);
    fn CGContextSetShouldSubpixelQuantizeFonts(c: CGContextRef,
                                               shouldSubpixelQuantizeFonts: bool);
    fn CGContextSetAllowsFontSubpixelPositioning(c: CGContextRef,
                                                 allowsFontSubpixelPositioning: bool);
    fn CGContextSetShouldSubpixelPositionFonts(c: CGContextRef,
                                               shouldSubpixelPositionFonts: bool);
    fn CGContextSetTextDrawingMode(c: CGContextRef, mode: CGTextDrawingMode);
    fn CGContextSetRGBFillColor(context: CGContextRef,
                                red: CGFloat,
                                green: CGFloat,
                                blue: CGFloat,
                                alpha: CGFloat);
    fn CGContextFillRect(context: CGContextRef,
                         rect: CGRect);
    fn CGContextDrawImage(c: CGContextRef, rect: CGRect, image: CGImageRef);
}

<|endoftext|>


<commit_before>use super::gl_lib as gl;
use super::buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use super::program::{ProgramBinder};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder
        }
    }

    pub fn clear_color(&mut self, color: super::Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: super::ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}
<commit_msg>Add `use_program!` macro<commit_after>use super::gl_lib as gl;
use super::buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use super::program::{ProgramBinder};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder
        }
    }

    pub fn clear_color(&mut self, color: super::Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: super::ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}
<|endoftext|>


<commit_before>use serialize::json::{Json, ToJson, Object};
use regex::Regex;
use std::collections::{VecDeque, BTreeMap};

/// The context wrap data you render on your templates.
///
#[derive(Debug)]
pub struct Context {
    data: Json,
    default: Json,
    key_matcher: Regex,
}

#[inline]
fn parse_json_visitor<'a>(path_stack: &mut VecDeque<&'a str>, path: &'a str) {
    for p in (*path).split('/') {
        match p {
            "." | "" => {
                continue;
            }
            ".." => {
                path_stack.pop_back();
            }
            _ => {
                for dot_p in p.split('.') {
//                    if dot_p != "this" {
                        path_stack.push_back(dot_p);
//                    }
                }
            }
        }
    }
}

fn merge_json(base: &Json, addition: &Object) -> Json {
    let mut base_map = match base {
        &Json::Object(ref m) => {
            m.clone()
        }
        _ => {
            let mut map: BTreeMap<String, Json> = BTreeMap::new();
            map.insert("this".to_owned(), base.clone());
            map
        }
    };

    for (k, v) in addition.iter() {
        base_map.insert(k.clone(), v.clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context {
            data: Json::Null,
            default: Json::Null,
            key_matcher: Regex::new(r"\[.+\]$").unwrap(),
        }
    }

    /// Create a context with given data
    pub fn wraps<T: ToJson>(e: &T) -> Context {
        Context {
            data: e.to_json(),
            default: Json::Null,
            key_matcher: Regex::new(r"\[.+\]$").unwrap(),
        }
    }

    /// Extend current context with another JSON object
    /// If current context is a JSON object, it's identical to a normal merge
    /// Otherwise, the current value will be stored in new JSON object with key `this`, and merged
    /// keys are also available.
    pub fn extend(&self, hash: &Object) -> Context {
        let new_data = merge_json(&self.data, hash);
        Context {
            data: new_data,
            default: Json::Null,
            key_matcher: Regex::new(r"\[.+\]$").unwrap()
        }
    }

    /// Navigate the context with base path and relative path
    /// Typically you will set base path to `RenderContext.get_path()`
    /// and set relative path to helper argument or so.
    ///
    /// If you want to navigate from top level, set the base path to `"."`
    pub fn navigate(&self, base_path: &str, relative_path: &str) -> &Json {
        let mut path_stack :VecDeque<&str> = VecDeque::new();
        parse_json_visitor(&mut path_stack, base_path);
        parse_json_visitor(&mut path_stack, relative_path);

        let paths :Vec<&str> = path_stack.iter().map(|x| *x).collect();
        let mut data: &Json = &self.data;
        for p in paths.iter() {
            match self.key_matcher.find(*p) {
                Some((s, _)) => {
                    let arr = &p[..s];
                    let idx = &p[s+1 .. p.len()-1];

                    let root = if arr == "this" || arr == "" {
                        Some(data)
                    } else {
                        data.find(arr)
                    };

                    data = match root {
                        Some(d) => {
                            match *d {
                                Json::Array(ref l) => {
                                    idx.parse::<usize>().and_then(
                                        |idx_u| Ok(l.get(idx_u).unwrap_or(&self.default)))
                                        .unwrap_or(&self.default)
                                },
                                _ => {
                                    &self.default
                                }
                            }
                        },
                        None => &self.default
                    };
                },
                None => {
                    data = match data.find(*p) {
                        Some(d) => d,
                        None => {
                            if *p == "this" {
                                data
                            } else {
                                &self.default
                            }
                        }
                    };
                }
            }
        }
        data
    }
}

pub trait JsonRender {
    fn render(&self) -> String;
}

pub trait JsonTruthy {
    fn is_truthy(&self) -> bool;
}

impl JsonRender for Json {
    fn render(&self) -> String {
        if let Json::String(_) = *self {
            self.as_string().unwrap_or("").to_string()
        } else {
            format!("{}", *self)
        }
    }
}

impl JsonTruthy for Json {
    fn is_truthy(&self) -> bool {
        match *self {
            Json::I64(i) => i != 0,
            Json::U64(i) => i != 0,
            Json::F64(i) => i != 0.0 || ! i.is_nan(),
            Json::Boolean (ref i) => *i,
            Json::Null => false,
            Json::String (ref i) => i.len() > 0,
            Json::Array (ref i) => i.len() > 0,
            Json::Object (ref i) => i.len() > 0
        }
    }
}

#[cfg(test)]
mod test {
    use context::{JsonRender, Context};
    use std::collections::BTreeMap;
    use serialize::json::{Json, ToJson};

    #[test]
    fn test_json_render() {
        let raw = "
Hello world
\n Json {
            let mut m = BTreeMap::new();
            m.insert("city".to_string(), self.city.to_json());
            m.insert("country".to_string(), self.country.to_json());
            Json::Object(m)
        }
    }

    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>
    }

    impl ToJson for Person {
        fn to_json(&self) -> Json {
            let mut m = BTreeMap::new();
            m.insert("name".to_string(), self.name.to_json());
            m.insert("age".to_string(), self.age.to_json());
            m.insert("addr".to_string(), self.addr.to_json());
            m.insert("titles".to_string(), self.titles.to_json());
            Json::Object(m)
        }
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string());
        assert_eq!(ctx.navigate(".", "this").render(), v.to_string());
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(),
                         "cartographier".to_string()]
        };

        let ctx = Context::wraps(&person);
        assert_eq!(ctx.navigate(".", "./name/../addr/country").render(), "China".to_string());

        let v = true;
        let ctx2 = Context::wraps(&v);
        assert_eq!(ctx2.navigate(".", "this").render(), "true".to_string());

        assert_eq!(ctx.navigate(".", "titles[0]").render(), "programmer".to_string());
        assert_eq!(ctx.navigate(".", "titles.[0]").render(), "programmer".to_string());
    }

    #[test]
    fn test_this() {
        let mut map_with_this = BTreeMap::new();
        map_with_this.insert("this".to_string(), "hello".to_json());
        map_with_this.insert("age".to_string(), 5usize.to_json());
        let ctx1 = Context::wraps(&map_with_this);

        let mut map_without_this = BTreeMap::new();
        map_without_this.insert("age".to_string(), 4usize.to_json());
        let ctx2 = Context::wraps(&map_without_this);

        assert_eq!(ctx1.navigate(".", "this").render(), "hello".to_owned());
        assert_eq!(ctx2.navigate(".", "age").render(), "4".to_owned());
    }

    #[test]
    fn test_extend() {
        let mut map = BTreeMap::new();
        map.insert("age".to_string(), 4usize.to_json());
        let ctx1 = Context::wraps(&map);

        let s = "hello".to_owned();
        let ctx2 = Context::wraps(&s);

        let mut hash = BTreeMap::new();
        hash.insert("tag".to_owned(), "h1".to_json());

        let ctx_a1 = ctx1.extend(&hash);
        assert_eq!(ctx_a1.navigate(".", "age").render(), "4".to_owned());
        assert_eq!(ctx_a1.navigate(".", "tag").render(), "h1".to_owned());

        let ctx_a2 = ctx2.extend(&hash);
        assert_eq!(ctx_a2.navigate(".", "this").render(), "hello".to_owned());
        assert_eq!(ctx_a2.navigate(".", "tag").render(), "h1".to_owned());
    }
}
<commit_msg>(refactoring) chained call<commit_after>use serialize::json::{Json, ToJson, Object};
use regex::Regex;
use std::collections::{VecDeque, BTreeMap};

/// The context wrap data you render on your templates.
///
#[derive(Debug)]
pub struct Context {
    data: Json,
    default: Json,
    key_matcher: Regex,
}

#[inline]
fn parse_json_visitor<'a>(path_stack: &mut VecDeque<&'a str>, path: &'a str) {
    for p in (*path).split('/') {
        match p {
            "." | "" => {
                continue;
            }
            ".." => {
                path_stack.pop_back();
            }
            _ => {
                for dot_p in p.split('.') {
//                    if dot_p != "this" {
                        path_stack.push_back(dot_p);
//                    }
                }
            }
        }
    }
}

fn merge_json(base: &Json, addition: &Object) -> Json {
    let mut base_map = match base {
        &Json::Object(ref m) => {
            m.clone()
        }
        _ => {
            let mut map: BTreeMap<String, Json> = BTreeMap::new();
            map.insert("this".to_owned(), base.clone());
            map
        }
    };

    for (k, v) in addition.iter() {
        base_map.insert(k.clone(), v.clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context {
            data: Json::Null,
            default: Json::Null,
            key_matcher: Regex::new(r"\[.+\]$").unwrap(),
        }
    }

    /// Create a context with given data
    pub fn wraps<T: ToJson>(e: &T) -> Context {
        Context {
            data: e.to_json(),
            default: Json::Null,
            key_matcher: Regex::new(r"\[.+\]$").unwrap(),
        }
    }

    /// Extend current context with another JSON object
    /// If current context is a JSON object, it's identical to a normal merge
    /// Otherwise, the current value will be stored in new JSON object with key `this`, and merged
    /// keys are also available.
    pub fn extend(&self, hash: &Object) -> Context {
        let new_data = merge_json(&self.data, hash);
        Context {
            data: new_data,
            default: Json::Null,
            key_matcher: Regex::new(r"\[.+\]$").unwrap()
        }
    }

    /// Navigate the context with base path and relative path
    /// Typically you will set base path to `RenderContext.get_path()`
    /// and set relative path to helper argument or so.
    ///
    /// If you want to navigate from top level, set the base path to `"."`
    pub fn navigate(&self, base_path: &str, relative_path: &str) -> &Json {
        let mut path_stack :VecDeque<&str> = VecDeque::new();
        parse_json_visitor(&mut path_stack, base_path);
        parse_json_visitor(&mut path_stack, relative_path);

        let paths :Vec<&str> = path_stack.iter().map(|x| *x).collect();
        let mut data: &Json = &self.data;
        for p in paths.iter() {
            match self.key_matcher.find(*p) {
                Some((s, _)) => {
                    let arr = &p[..s];
                    let idx = &p[s+1 .. p.len()-1];

                    let root = match arr{
                        "this" | "" => Some(data),
                        _ => data.find(arr)
                    };

                    data = match root {
                        Some(d) => {
                            match *d {
                                Json::Array(ref l) => {
                                    idx.parse::<usize>().and_then(
                                        |idx_u| Ok(l.get(idx_u).unwrap_or(&self.default)))
                                        .unwrap_or(&self.default)
                                },
                                _ => {
                                    &self.default
                                }
                            }
                        },
                        None => &self.default
                    };
                },
                None => {
                    data = data.find(*p)
                        .unwrap_or_else(|| if *p == "this" {
                            data
                        } else {
                            &self.default
                        });
                }
            }
        }
        data
    }
}

pub trait JsonRender {
    fn render(&self) -> String;
}

pub trait JsonTruthy {
    fn is_truthy(&self) -> bool;
}

impl JsonRender for Json {
    fn render(&self) -> String {
        if let Json::String(_) = *self {
            self.as_string().unwrap_or("").to_string()
        } else {
            format!("{}", *self)
        }
    }
}

impl JsonTruthy for Json {
    fn is_truthy(&self) -> bool {
        match *self {
            Json::I64(i) => i != 0,
            Json::U64(i) => i != 0,
            Json::F64(i) => i != 0.0 || ! i.is_nan(),
            Json::Boolean (ref i) => *i,
            Json::Null => false,
            Json::String (ref i) => i.len() > 0,
            Json::Array (ref i) => i.len() > 0,
            Json::Object (ref i) => i.len() > 0
        }
    }
}

#[cfg(test)]
mod test {
    use context::{JsonRender, Context};
    use std::collections::BTreeMap;
    use serialize::json::{Json, ToJson};

    #[test]
    fn test_json_render() {
        let raw = "
Hello world
\n Json {
            let mut m = BTreeMap::new();
            m.insert("city".to_string(), self.city.to_json());
            m.insert("country".to_string(), self.country.to_json());
            Json::Object(m)
        }
    }

    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>
    }

    impl ToJson for Person {
        fn to_json(&self) -> Json {
            let mut m = BTreeMap::new();
            m.insert("name".to_string(), self.name.to_json());
            m.insert("age".to_string(), self.age.to_json());
            m.insert("addr".to_string(), self.addr.to_json());
            m.insert("titles".to_string(), self.titles.to_json());
            Json::Object(m)
        }
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string());
        assert_eq!(ctx.navigate(".", "this").render(), v.to_string());
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(),
                         "cartographier".to_string()]
        };

        let ctx = Context::wraps(&person);
        assert_eq!(ctx.navigate(".", "./name/../addr/country").render(), "China".to_string());

        let v = true;
        let ctx2 = Context::wraps(&v);
        assert_eq!(ctx2.navigate(".", "this").render(), "true".to_string());

        assert_eq!(ctx.navigate(".", "titles[0]").render(), "programmer".to_string());
        assert_eq!(ctx.navigate(".", "titles.[0]").render(), "programmer".to_string());
    }

    #[test]
    fn test_this() {
        let mut map_with_this = BTreeMap::new();
        map_with_this.insert("this".to_string(), "hello".to_json());
        map_with_this.insert("age".to_string(), 5usize.to_json());
        let ctx1 = Context::wraps(&map_with_this);

        let mut map_without_this = BTreeMap::new();
        map_without_this.insert("age".to_string(), 4usize.to_json());
        let ctx2 = Context::wraps(&map_without_this);

        assert_eq!(ctx1.navigate(".", "this").render(), "hello".to_owned());
        assert_eq!(ctx2.navigate(".", "age").render(), "4".to_owned());
    }

    #[test]
    fn test_extend() {
        let mut map = BTreeMap::new();
        map.insert("age".to_string(), 4usize.to_json());
        let ctx1 = Context::wraps(&map);

        let s = "hello".to_owned();
        let ctx2 = Context::wraps(&s);

        let mut hash = BTreeMap::new();
        hash.insert("tag".to_owned(), "h1".to_json());

        let ctx_a1 = ctx1.extend(&hash);
        assert_eq!(ctx_a1.navigate(".", "age").render(), "4".to_owned());
        assert_eq!(ctx_a1.navigate(".", "tag").render(), "h1".to_owned());

        let ctx_a2 = ctx2.extend(&hash);
        assert_eq!(ctx_a2.navigate(".", "this").render(), "hello".to_owned());
        assert_eq!(ctx_a2.navigate(".", "tag").render(), "h1".to_owned());
    }
}
<|endoftext|>


<commit_before>extern crate c_ares_sys;
extern crate libc;

use std::ffi::CString;
use std::mem;
use std::os::unix::io;
use std::ptr;

use callbacks::{
    socket_callback,
    query_a_callback,
    query_aaaa_callback,
};
use types::{
    Flag,
    AresError,
    AResult,
    AAAAResult,
    DnsClass,
    QueryType,
};
use utils::ares_error;

/// Used to configure the behaviour of the name resolver.
pub struct Options {
    ares_options: c_ares_sys::Struct_ares_options,
    optmask: libc::c_int,
}

impl Options {
    /// Returns a fresh `Options`, on which no values are set.
    pub fn new() -> Options {
        Options {
            ares_options: c_ares_sys::Struct_ares_options::default(),
            optmask: 0,
        }
    }

    /// Set flags controlling the behaviour of the resolver.
    pub fn set_flags(&mut self, flags: &[Flag]) -> &mut Self {
        let c_flags: libc::c_int = flags
            .iter()
            .fold(0, |acc, &flag| acc | (flag as libc::c_int));
        self.ares_options.flags = c_flags;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_FLAGS;
        self
    }

    /// Set the number of milliseconds each name server is given to respond to
    /// a query on the first try.  (After the first try, the timeout algorithm
    /// becomes more complicated, but scales linearly with the value of
    /// timeout.) The default is five seconds.
    pub fn set_timeout(&mut self, ms: u32) -> &mut Self {
        self.ares_options.timeout = ms as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TIMEOUTMS;
        self
    }

    /// Set the number of tries the resolver will try contacting each name
    /// server before giving up. The default is four tries.
    pub fn set_tries(&mut self, tries: u32) -> &mut Self {
        self.ares_options.tries = tries as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TRIES;
        self
    }

    /// Set the number of dots which must be present in a domain name for it to
    /// be queried for "as is" prior to querying for it with the default domain
    /// extensions appended. The default value is 1 unless set otherwise by
    /// resolv.conf or the RES_OPTIONS environment variable.
    pub fn set_ndots(&mut self, ndots: u32) -> &mut Self {
        self.ares_options.ndots = ndots as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_NDOTS;
        self
    }

    /// Set the UDP port to use for queries. The default value is 53, the
    /// standard name service port.
    pub fn set_udp_port(&mut self, udp_port: u16) -> &mut Self {
        self.ares_options.udp_port = udp_port as libc::c_ushort;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_UDP_PORT;
        self
    }

    /// Set the TCP port to use for queries. The default value is 53, the
    /// standard name service port.
    pub fn set_tcp_port(&mut self, tcp_port: u16) -> &mut Self {
        self.ares_options.tcp_port = tcp_port as libc::c_ushort;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TCP_PORT;
        self
    }
}

/// A channel for name service lookups.
pub struct Channel {
    ares_channel: c_ares_sys::ares_channel,
}

impl Channel {
    /// Create a new channel for name service lookups, providing a callback
    /// for socket state changes.
    ///
    /// `callback(socket, read, write)` will be called when a socket changes
    /// state:
    ///
    /// -  `read` is set to true if the socket should listen for read events
    /// -  `write` is set to true if the socket should listen to write events.
    pub fn new<F>(
        callback: F,
        mut options: Options) -> Result<Channel, AresError>
        where F: FnMut(io::RawFd, bool, bool) + 'static {
        options.optmask = options.optmask | c_ares_sys::ARES_OPT_SOCK_STATE_CB;
        options.ares_options.sock_state_cb = Some(socket_callback::<F>);
        options.ares_options.sock_state_cb_data = unsafe {
            mem::transmute(Box::new(callback))
        };
        Self::create_channel(options)
    }

    fn create_channel(mut options: Options) -> Result<Channel, AresError> {
        let lib_rc = unsafe {
            c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL)
        };
        if lib_rc != c_ares_sys::ARES_SUCCESS {
            return Err(ares_error(lib_rc))
        }

        let mut ares_channel = ptr::null_mut();
        let channel_rc = unsafe {
            c_ares_sys::ares_init_options(
                &mut ares_channel,
                &mut options.ares_options,
                options.optmask)
        };
        if channel_rc != c_ares_sys::ARES_SUCCESS {
            unsafe { c_ares_sys::ares_library_cleanup(); }
            return Err(ares_error(channel_rc))
        }

        let channel = Channel {
            ares_channel: ares_channel,
        };
        Ok(channel)
    }

    /// Handle input, output, and timeout events associated with the specified
    /// file descriptors (sockets).
    ///
    /// Providing a value for `read_fd` indicates that the identified socket
    /// is readable; likewise providing a value for `write_fd` indicates that
    /// the identified socket is writable.  Use `INVALID_FD` for "no action".
    pub fn process_fd(&mut self, read_fd: io::RawFd, write_fd: io::RawFd) {
        unsafe {
            c_ares_sys::ares_process_fd(
                self.ares_channel,
                read_fd as c_ares_sys::ares_socket_t,
                write_fd as c_ares_sys::ares_socket_t);
        }
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(&mut self, servers: &[&str]) -> Result<(), AresError> {
        let servers_csv = servers.connect(",");
        let c_servers = CString::new(servers_csv).unwrap();
        let ares_rc = unsafe {
            c_ares_sys::ares_set_servers_csv(
                self.ares_channel,
                c_servers.as_ptr())
        };
        if ares_rc != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(ares_rc))
        } else {
            Ok(())
        }
    }

    /// Look up the A record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_a<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::A as libc::c_int,
                Some(query_a_callback::<F>),
                c_arg);
        }
    }

    /// Look up the AAAA record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::AAAA as libc::c_int,
                Some(query_aaaa_callback::<F>),
                c_arg);
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_destroy(self.ares_channel);
            c_ares_sys::ares_library_cleanup();
        }
    }
}

unsafe impl Send for Channel { }
<commit_msg>Setting more options<commit_after>extern crate c_ares_sys;
extern crate libc;

use std::ffi::CString;
use std::mem;
use std::os::unix::io;
use std::ptr;

use callbacks::{
    socket_callback,
    query_a_callback,
    query_aaaa_callback,
};
use types::{
    Flag,
    AresError,
    AResult,
    AAAAResult,
    DnsClass,
    QueryType,
};
use utils::ares_error;

/// Used to configure the behaviour of the name resolver.
pub struct Options {
    ares_options: c_ares_sys::Struct_ares_options,
    optmask: libc::c_int,
}

impl Options {
    /// Returns a fresh `Options`, on which no values are set.
    pub fn new() -> Options {
        Options {
            ares_options: c_ares_sys::Struct_ares_options::default(),
            optmask: 0,
        }
    }

    /// Set flags controlling the behaviour of the resolver.
    pub fn set_flags(&mut self, flags: &[Flag]) -> &mut Self {
        let c_flags: libc::c_int = flags
            .iter()
            .fold(0, |acc, &flag| acc | (flag as libc::c_int));
        self.ares_options.flags = c_flags;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_FLAGS;
        self
    }

    /// Set the number of milliseconds each name server is given to respond to
    /// a query on the first try.  (After the first try, the timeout algorithm
    /// becomes more complicated, but scales linearly with the value of
    /// timeout.) The default is five seconds.
    pub fn set_timeout(&mut self, ms: u32) -> &mut Self {
        self.ares_options.timeout = ms as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TIMEOUTMS;
        self
    }

    /// Set the number of tries the resolver will try contacting each name
    /// server before giving up. The default is four tries.
    pub fn set_tries(&mut self, tries: u32) -> &mut Self {
        self.ares_options.tries = tries as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TRIES;
        self
    }

    /// Set the number of dots which must be present in a domain name for it to
    /// be queried for "as is" prior to querying for it with the default domain
    /// extensions appended. The default value is 1 unless set otherwise by
    /// resolv.conf or the RES_OPTIONS environment variable.
    pub fn set_ndots(&mut self, ndots: u32) -> &mut Self {
        self.ares_options.ndots = ndots as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_NDOTS;
        self
    }

    /// Set the UDP port to use for queries. The default value is 53, the
    /// standard name service port.
    pub fn set_udp_port(&mut self, udp_port: u16) -> &mut Self {
        self.ares_options.udp_port = udp_port as libc::c_ushort;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_UDP_PORT;
        self
    }

    /// Set the TCP port to use for queries. The default value is 53, the
    /// standard name service port.
    pub fn set_tcp_port(&mut self, tcp_port: u16) -> &mut Self {
        self.ares_options.tcp_port = tcp_port as libc::c_ushort;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_TCP_PORT;
        self
    }

    // TODO set_domains and set_lookups()

    /// Set the socket send buffer size.
    pub fn set_sock_send_buffer_size(&mut self, size: u32) -> &mut Self {
        self.ares_options.socket_send_buffer_size = size as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_SOCK_SNDBUF;
        self
    }

    /// Set the socket receive buffer size.
    pub fn set_sock_receive_buffer_size(&mut self, size: u32) -> &mut Self {
        self.ares_options.socket_receive_buffer_size = size as libc::c_int;
        self.optmask = self.optmask | c_ares_sys::ARES_OPT_SOCK_RCVBUF;
        self
    }
}

/// A channel for name service lookups.
pub struct Channel {
    ares_channel: c_ares_sys::ares_channel,
}

impl Channel {
    /// Create a new channel for name service lookups, providing a callback
    /// for socket state changes.
    ///
    /// `callback(socket, read, write)` will be called when a socket changes
    /// state:
    ///
    /// -  `read` is set to true if the socket should listen for read events
    /// -  `write` is set to true if the socket should listen to write events.
    pub fn new<F>(
        callback: F,
        mut options: Options) -> Result<Channel, AresError>
        where F: FnMut(io::RawFd, bool, bool) + 'static {
        options.optmask = options.optmask | c_ares_sys::ARES_OPT_SOCK_STATE_CB;
        options.ares_options.sock_state_cb = Some(socket_callback::<F>);
        options.ares_options.sock_state_cb_data = unsafe {
            mem::transmute(Box::new(callback))
        };
        Self::create_channel(options)
    }

    fn create_channel(mut options: Options) -> Result<Channel, AresError> {
        let lib_rc = unsafe {
            c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL)
        };
        if lib_rc != c_ares_sys::ARES_SUCCESS {
            return Err(ares_error(lib_rc))
        }

        let mut ares_channel = ptr::null_mut();
        let channel_rc = unsafe {
            c_ares_sys::ares_init_options(
                &mut ares_channel,
                &mut options.ares_options,
                options.optmask)
        };
        if channel_rc != c_ares_sys::ARES_SUCCESS {
            unsafe { c_ares_sys::ares_library_cleanup(); }
            return Err(ares_error(channel_rc))
        }

        let channel = Channel {
            ares_channel: ares_channel,
        };
        Ok(channel)
    }

    /// Handle input, output, and timeout events associated with the specified
    /// file descriptors (sockets).
    ///
    /// Providing a value for `read_fd` indicates that the identified socket
    /// is readable; likewise providing a value for `write_fd` indicates that
    /// the identified socket is writable.  Use `INVALID_FD` for "no action".
    pub fn process_fd(&mut self, read_fd: io::RawFd, write_fd: io::RawFd) {
        unsafe {
            c_ares_sys::ares_process_fd(
                self.ares_channel,
                read_fd as c_ares_sys::ares_socket_t,
                write_fd as c_ares_sys::ares_socket_t);
        }
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(&mut self, servers: &[&str]) -> Result<(), AresError> {
        let servers_csv = servers.connect(",");
        let c_servers = CString::new(servers_csv).unwrap();
        let ares_rc = unsafe {
            c_ares_sys::ares_set_servers_csv(
                self.ares_channel,
                c_servers.as_ptr())
        };
        if ares_rc != c_ares_sys::ARES_SUCCESS {
            Err(ares_error(ares_rc))
        } else {
            Ok(())
        }
    }

    /// Look up the A record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_a<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::A as libc::c_int,
                Some(query_a_callback::<F>),
                c_arg);
        }
    }

    /// Look up the AAAA record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::AAAA as libc::c_int,
                Some(query_aaaa_callback::<F>),
                c_arg);
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_destroy(self.ares_channel);
            c_ares_sys::ares_library_cleanup();
        }
    }
}

unsafe impl Send for Channel { }
<|endoftext|>


<commit_before>const INTERPRETER_START: u32 = 0x000;
const INTERPRETER_END: u32 = 0x1FF;
const INTERPRETER_LENGTH: u32 = INTERPRETER_END - INTERPRETER_START;

const FONT_SET_START: usize = 0x050;
const FONT_SET_END: usize = 0x0A0;
const FONT_SET_LENGTH: usize = FONT_SET_END - FONT_SET_START;

const DATA_START: usize = 0x200;
const DATA_END: usize = 0xFFF;
const DATA_LENGTH: usize = DATA_END - DATA_START;

const MEM_LENGTH: usize = 4096;
const STACK_LEVEL: usize = 16;
const REG_NUM: usize = 16;
pub const GFX_WIDTH: usize = 64;
pub const GFX_HEIGHT: usize = 32;

const FONTSET: [u8; 80] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80  // F
];

pub fn init() -> Cpu {
    let mut ret = Cpu {
        pc: 0x200,
        opcode: 0,
        memory: vec![0; MEM_LENGTH],
        reg: vec![0; REG_NUM],
        index: 0,
        sp: 0,
        stack: vec![0; STACK_LEVEL],
        // gfx: vec![vec![0; GFX_HEIGHT]; GFX_WIDTH],
        gfx: vec![0; GFX_WIDTH * GFX_HEIGHT],
        delay_timer: 0,
        sound_timer: 0,
        key: vec![0; STACK_LEVEL],
    };
    ret.load_fontset();
    ret
}

#[derive(Debug, Clone)]
pub struct Cpu {
    pc: usize,
    opcode: u16,
    memory: Vec<u8>,
    reg: Vec<u8>,
    index: usize,
    // gfx: Vec<Vec<u8>>,
    gfx: Vec<u8>,
    delay_timer: u8,
    sound_timer: u8,
    stack: Vec<usize>,
    sp: usize,
    key: Vec<u8>,
}

impl Cpu {
    fn load_fontset(&mut self) {
        for i in 0..FONT_SET_LENGTH {
            self.memory[FONT_SET_START + i] = FONTSET[i];
        }
    }

    pub fn load_rom(&mut self, rom: Box<[u8]>) {
        for i in 0..rom.len() {
            self.memory[DATA_START + i] = rom[i];
        }
    }

    pub fn curr_pc(&mut self) -> usize {
        self.pc
    }

    pub fn curr_index(&mut self) -> usize {
        self.index
    }

    pub fn curr_opcode(&mut self) -> u16 {
        self.opcode
    }

    pub fn curr_regs(&mut self) -> Vec<u8> {
        self.clone().reg
    }

    pub fn curr_stack(&mut self) -> Vec<usize> {
        self.clone().stack
    }

    pub fn curr_sp(&mut self) -> usize {
        self.sp
    }

    pub fn curr_gfx(&mut self) -> Vec<u8> {
        self.clone().gfx
    }

    pub fn emulate_cycle(&mut self) {
        self.opcode = (self.memory[self.pc] as u16) << 8 | (self.memory[self.pc+1] as u16);

        match self.opcode & 0xF000 {
            0x0000 => {
                match self.opcode & 0x0F00 {
                    0x0000 => {
                        match self.opcode & 0x00FF {
                            0x00EE => { // 00EE: return from subroutine
                                self.sp -= 1;
                                self.pc = self.stack[self.sp];
                            },
                            0x00E0 => { // 00E0: clear screen
                                self.gfx = vec![0; GFX_HEIGHT *  GFX_WIDTH];
                                self.pc += 2;
                            },
                            _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
                        }
                    },
                    _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
                }
            },
            0x1000 => { // 1NNN: jump to NNN
                let addr = self.opcode & 0x0FFF;
                self.pc = addr as usize;
            },
            0x2000 => { // 2NNN: Calls subroutine at NNN
                let addr = self.opcode & 0x0FFF;
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr as usize;
            },
            0x3000 => { // 3XNN: skip next if VX == NN
                let x = (self.opcode & 0x0F00) >> 8;
                let nn = self.opcode & 0x00FF;
                if self.reg[x as usize] == nn as u8 {
                    self.pc += 4;
                } else {
                    self.pc += 2;
                }
            },
            0x4000 => { // 4XNN: skip next if VX != NN
                let x = (self.opcode & 0x0F00) >> 8;
                let nn = self.opcode & 0x00FF;
                if self.reg[x as usize] != nn as u8 {
                    self.pc += 4;
                } else {
                    self.pc += 2;
                }
            },
            0x6000 => { // 6XNN: Sets VX to NN
                let index = (self.opcode & 0x0F00) >> 8;
                let val = self.opcode & 0x00FF;
                self.reg[index as usize] = val as u8;
                self.pc += 2;
            },
            0x7000 => { // 7XNN: Adds NN to VX
                let x = (self.opcode & 0x0F00) >> 8;
                let nn = self.opcode & 0x00FF;
                self.reg[x as usize] += nn as u8;
                self.pc += 2;
            },
            0x8000 => {
                match self.opcode & 0x000F {
                    0x0000 => { // 8XY0: set VX to VY
                        let x = (self.opcode & 0x0F00) >> 8;
                        let y = (self.opcode & 0x00F0) >> 4;
                        self.reg[x as usize] = self.reg[y as usize];
                        self.pc += 2;
                    },
                    0x0002 => { // 8XY2: set VX to VX & VY
                        let x = (self.opcode & 0x0F00) >> 8;
                        let y = (self.opcode & 0x00F0) >> 4;
                        self.reg[x as usize] = self.reg[x as usize] & self.reg[y as usize];
                        self.reg[0xF] = 0;
                        self.pc += 2;
                    },
                    0x0004 => { // 8XY4: add VY to VX
                        let x = (self.opcode & 0x0F00) >> 8;
                        let y = (self.opcode & 0x00F0) >> 4;
                        let tmp = (self.reg[x as usize] as u16) + (self.reg[y as usize] as u16);
                        if tmp > 0x00FF {
                            self.reg[0xF] = 1;
                        } else {
                            self.reg[0xF] = 0;
                        }
                        self.reg[x as usize] = tmp as u8;
                        self.pc += 2;
                    },
                    _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
                }
            },
            0xA000 => { // ANNN: Sets I to the address NNN
                let val = self.opcode & 0x0FFF;
                self.index = val as usize;
                self.pc += 2;
            },
            0xD000 => { // DXYN: Draws sprite at cordinate VX, VY with height N
                let x = (self.opcode & 0x0F00) >> 8;
                let y = (self.opcode & 0x00F0) >> 4;
                let n = self.opcode & 0x000F;
                let mut pix: u8;

                let tmp = self.index as usize;
                let sprite = &self.memory[tmp..(tmp + (n as usize))];

                self.reg[0xF] = 0;
                for i in 0..n {
                    pix = (&sprite)[i as usize];
                    for j in 0..8 {
                        if (pix & (0x80 >> j)) != 0 {
                            if self.gfx[(x + j + ((y + i) * 64)) as usize] == 1 {
                                self.reg[0xF] = 1;
                            }
                            self.gfx[(x + j + ((y + i) * 64)) as usize] ^= 1;
                        }
                    }
                }
                self.pc += 2;
            },
            0xF000 => {
                match self.opcode & 0x00FF {
                    0x0029 => { // FX29: set I to character sprite in VX
                        let x = (self.opcode & 0x0F00) >> 8;
                        let tmp = FONT_SET_START + ((self.reg[x as usize] * 5) as usize);
                        self.index = self.memory[tmp] as usize;
                        self.pc += 2;
                    },
                    0x0033 => { // FX33: set memory at I:I+2 to VX
                        let x = (self.opcode & 0x0F00) >> 8;
                        let val = self.reg[x as usize];
                        self.memory[self.index] = val / 100;
                        self.memory[self.index + 1] = (val / 10) % 10;
                        self.memory[self.index + 2] = val % 10;
                        self.pc += 2;
                    },
                    0x0065 => { // FX65: fill V0 to VX with values at I:I+X
                        let x = (self.opcode & 0x0F00) >> 8;
                        for i in 0..x {
                            self.reg[i as usize] = self.memory[self.index + (i as usize)];
                        }
                        self.pc += 2;
                    },
                    _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
                }
            },
            _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
        }
    }
}
<commit_msg>Add opcode FX1E (add VX to I)<commit_after>const INTERPRETER_START: u32 = 0x000;
const INTERPRETER_END: u32 = 0x1FF;
const INTERPRETER_LENGTH: u32 = INTERPRETER_END - INTERPRETER_START;

const FONT_SET_START: usize = 0x050;
const FONT_SET_END: usize = 0x0A0;
const FONT_SET_LENGTH: usize = FONT_SET_END - FONT_SET_START;

const DATA_START: usize = 0x200;
const DATA_END: usize = 0xFFF;
const DATA_LENGTH: usize = DATA_END - DATA_START;

const MEM_LENGTH: usize = 4096;
const STACK_LEVEL: usize = 16;
const REG_NUM: usize = 16;
pub const GFX_WIDTH: usize = 64;
pub const GFX_HEIGHT: usize = 32;

const FONTSET: [u8; 80] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80  // F
];

pub fn init() -> Cpu {
    let mut ret = Cpu {
        pc: 0x200,
        opcode: 0,
        memory: vec![0; MEM_LENGTH],
        reg: vec![0; REG_NUM],
        index: 0,
        sp: 0,
        stack: vec![0; STACK_LEVEL],
        // gfx: vec![vec![0; GFX_HEIGHT]; GFX_WIDTH],
        gfx: vec![0; GFX_WIDTH * GFX_HEIGHT],
        delay_timer: 0,
        sound_timer: 0,
        key: vec![0; STACK_LEVEL],
    };
    ret.load_fontset();
    ret
}

#[derive(Debug, Clone)]
pub struct Cpu {
    pc: usize,
    opcode: u16,
    memory: Vec<u8>,
    reg: Vec<u8>,
    index: usize,
    // gfx: Vec<Vec<u8>>,
    gfx: Vec<u8>,
    delay_timer: u8,
    sound_timer: u8,
    stack: Vec<usize>,
    sp: usize,
    key: Vec<u8>,
}

impl Cpu {
    fn load_fontset(&mut self) {
        for i in 0..FONT_SET_LENGTH {
            self.memory[FONT_SET_START + i] = FONTSET[i];
        }
    }

    pub fn load_rom(&mut self, rom: Box<[u8]>) {
        for i in 0..rom.len() {
            self.memory[DATA_START + i] = rom[i];
        }
    }

    pub fn curr_pc(&mut self) -> usize {
        self.pc
    }

    pub fn curr_index(&mut self) -> usize {
        self.index
    }

    pub fn curr_opcode(&mut self) -> u16 {
        self.opcode
    }

    pub fn curr_regs(&mut self) -> Vec<u8> {
        self.clone().reg
    }

    pub fn curr_stack(&mut self) -> Vec<usize> {
        self.clone().stack
    }

    pub fn curr_sp(&mut self) -> usize {
        self.sp
    }

    pub fn curr_gfx(&mut self) -> Vec<u8> {
        self.clone().gfx
    }

    pub fn emulate_cycle(&mut self) {
        self.opcode = (self.memory[self.pc] as u16) << 8 | (self.memory[self.pc+1] as u16);

        match self.opcode & 0xF000 {
            0x0000 => {
                match self.opcode & 0x0F00 {
                    0x0000 => {
                        match self.opcode & 0x00FF {
                            0x00EE => { // 00EE: return from subroutine
                                self.sp -= 1;
                                self.pc = self.stack[self.sp];
                            },
                            0x00E0 => { // 00E0: clear screen
                                self.gfx = vec![0; GFX_HEIGHT *  GFX_WIDTH];
                                self.pc += 2;
                            },
                            _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
                        }
                    },
                    _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
                }
            },
            0x1000 => { // 1NNN: jump to NNN
                let addr = self.opcode & 0x0FFF;
                self.pc = addr as usize;
            },
            0x2000 => { // 2NNN: Calls subroutine at NNN
                let addr = self.opcode & 0x0FFF;
                self.stack[self.sp] = self.pc;
                self.sp += 1;
                self.pc = addr as usize;
            },
            0x3000 => { // 3XNN: skip next if VX == NN
                let x = (self.opcode & 0x0F00) >> 8;
                let nn = self.opcode & 0x00FF;
                if self.reg[x as usize] == nn as u8 {
                    self.pc += 4;
                } else {
                    self.pc += 2;
                }
            },
            0x4000 => { // 4XNN: skip next if VX != NN
                let x = (self.opcode & 0x0F00) >> 8;
                let nn = self.opcode & 0x00FF;
                if self.reg[x as usize] != nn as u8 {
                    self.pc += 4;
                } else {
                    self.pc += 2;
                }
            },
            0x6000 => { // 6XNN: Sets VX to NN
                let index = (self.opcode & 0x0F00) >> 8;
                let val = self.opcode & 0x00FF;
                self.reg[index as usize] = val as u8;
                self.pc += 2;
            },
            0x7000 => { // 7XNN: Adds NN to VX
                let x = (self.opcode & 0x0F00) >> 8;
                let nn = self.opcode & 0x00FF;
                self.reg[x as usize] += nn as u8;
                self.pc += 2;
            },
            0x8000 => {
                match self.opcode & 0x000F {
                    0x0000 => { // 8XY0: set VX to VY
                        let x = (self.opcode & 0x0F00) >> 8;
                        let y = (self.opcode & 0x00F0) >> 4;
                        self.reg[x as usize] = self.reg[y as usize];
                        self.pc += 2;
                    },
                    0x0002 => { // 8XY2: set VX to VX & VY
                        let x = (self.opcode & 0x0F00) >> 8;
                        let y = (self.opcode & 0x00F0) >> 4;
                        self.reg[x as usize] = self.reg[x as usize] & self.reg[y as usize];
                        self.reg[0xF] = 0;
                        self.pc += 2;
                    },
                    0x0004 => { // 8XY4: add VY to VX
                        let x = (self.opcode & 0x0F00) >> 8;
                        let y = (self.opcode & 0x00F0) >> 4;
                        let tmp = (self.reg[x as usize] as u16) + (self.reg[y as usize] as u16);
                        if tmp > 0x00FF {
                            self.reg[0xF] = 1;
                        } else {
                            self.reg[0xF] = 0;
                        }
                        self.reg[x as usize] = tmp as u8;
                        self.pc += 2;
                    },
                    _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
                }
            },
            0xA000 => { // ANNN: Sets I to the address NNN
                let val = self.opcode & 0x0FFF;
                self.index = val as usize;
                self.pc += 2;
            },
            0xD000 => { // DXYN: Draws sprite at cordinate VX, VY with height N
                let x = (self.opcode & 0x0F00) >> 8;
                let y = (self.opcode & 0x00F0) >> 4;
                let n = self.opcode & 0x000F;
                let mut pix: u8;

                let tmp = self.index as usize;
                let sprite = &self.memory[tmp..(tmp + (n as usize))];

                self.reg[0xF] = 0;
                for i in 0..n {
                    pix = (&sprite)[i as usize];
                    for j in 0..8 {
                        if (pix & (0x80 >> j)) != 0 {
                            if self.gfx[(x + j + ((y + i) * 64)) as usize] == 1 {
                                self.reg[0xF] = 1;
                            }
                            self.gfx[(x + j + ((y + i) * 64)) as usize] ^= 1;
                        }
                    }
                }
                self.pc += 2;
            },
            0xF000 => {
                match self.opcode & 0x00FF {
                    0x001E => { // FX1E: add VX to I
                        let x = (self.opcode & 0x0F00) >> 8;
                        self.index += x as usize;
                        self.pc += 2;
                    },
                    0x0029 => { // FX29: set I to character sprite in VX
                        let x = (self.opcode & 0x0F00) >> 8;
                        let tmp = FONT_SET_START + ((self.reg[x as usize] * 5) as usize);
                        self.index = self.memory[tmp] as usize;
                        self.pc += 2;
                    },
                    0x0033 => { // FX33: set memory at I:I+2 to VX
                        let x = (self.opcode & 0x0F00) >> 8;
                        let val = self.reg[x as usize];
                        self.memory[self.index] = val / 100;
                        self.memory[self.index + 1] = (val / 10) % 10;
                        self.memory[self.index + 2] = val % 10;
                        self.pc += 2;
                    },
                    0x0065 => { // FX65: fill V0 to VX with values at I:I+X
                        let x = (self.opcode & 0x0F00) >> 8;
                        for i in 0..x {
                            self.reg[i as usize] = self.memory[self.index + (i as usize)];
                        }
                        self.pc += 2;
                    },
                    _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
                }
            },
            _ => panic!("Unknown opcode or not implemented yet: {:X}", self.opcode)
        }
    }
}
<|endoftext|>


<commit_before>extern crate c_ares_sys;
extern crate libc;

use std::ffi::CString;
use std::mem;
use std::os::unix::io;
use std::ptr;

use callbacks::{
    socket_callback,
    query_a_callback,
    query_aaaa_callback,
};
use types::{
    AresError,
    AResult,
    AAAAResult,
    DnsClass,
    QueryType,
};
use utils::ares_error;

/// A channel for name service lookups.
pub struct Channel {
    ares_channel: c_ares_sys::ares_channel,
}

impl Channel {
    /// Create a new channel for name service lookups.
    ///
    /// `callback(socket, read, write)` will be called when a socket changes
    /// state:
    ///
    /// -  `read` is set to true if the socket should listen for read events
    /// -  `write` is set to true if the socket should listen to write events.
    pub fn new<F>(callback: F) -> Result<Channel, AresError>
        where F: FnMut(io::RawFd, bool, bool) + 'static {
        let lib_rc = unsafe {
            c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL)
        };
        if lib_rc != c_ares_sys::ARES_SUCCESS {
            return Err(ares_error(lib_rc))
        }

        // TODO suport user-provided options
        let mut ares_channel = ptr::null_mut();
        let mut options = c_ares_sys::Struct_ares_options::default();
        options.flags = c_ares_sys::ARES_FLAG_STAYOPEN;
        options.timeout = 500;
        options.tries = 3;
        options.sock_state_cb = Some(socket_callback::<F>);
        options.sock_state_cb_data = unsafe { mem::transmute(Box::new(callback)) };
        let optmask =
            c_ares_sys::ARES_OPT_FLAGS |
            c_ares_sys::ARES_OPT_TIMEOUTMS |
            c_ares_sys::ARES_OPT_TRIES |
            c_ares_sys::ARES_OPT_SOCK_STATE_CB;
        let channel_rc = unsafe {
            c_ares_sys::ares_init_options(&mut ares_channel, &mut options, optmask)
        };
        if channel_rc != c_ares_sys::ARES_SUCCESS {
            unsafe { c_ares_sys::ares_library_cleanup(); }
            return Err(ares_error(channel_rc))
        }

        let channel = Channel {
            ares_channel: ares_channel,
        };

        // TODO ares_set_servers() here too?
        Ok(channel)
    }

    /// Handle input, output, and timeout events associated with the specified
    /// file descriptors (sockets).
    ///
    /// Providing a value for `read_fd` indicates that the identified socket
    /// is readable; likewise providing a value for `write_fd` indicates that
    /// the identified socket is writable.  Use `INVALID_FD` for "no-action".
    pub fn process_fd(&mut self, read_fd: io::RawFd, write_fd: io::RawFd) {
        unsafe {
            c_ares_sys::ares_process_fd(
                self.ares_channel,
                read_fd as c_ares_sys::ares_socket_t,
                write_fd as c_ares_sys::ares_socket_t);
        }
    }

    /// Lookup the A record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_a<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::A as libc::c_int,
                Some(query_a_callback::<F>),
                c_arg);
        }
    }

    /// Lookup the AAAA record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::AAAA as libc::c_int,
                Some(query_aaaa_callback::<F>),
                c_arg);
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_destroy(self.ares_channel);
            c_ares_sys::ares_library_cleanup();
        }
    }
}

unsafe impl Send for Channel { }
<commit_msg>s/Lookup/Look up<commit_after>extern crate c_ares_sys;
extern crate libc;

use std::ffi::CString;
use std::mem;
use std::os::unix::io;
use std::ptr;

use callbacks::{
    socket_callback,
    query_a_callback,
    query_aaaa_callback,
};
use types::{
    AresError,
    AResult,
    AAAAResult,
    DnsClass,
    QueryType,
};
use utils::ares_error;

/// A channel for name service lookups.
pub struct Channel {
    ares_channel: c_ares_sys::ares_channel,
}

impl Channel {
    /// Create a new channel for name service lookups.
    ///
    /// `callback(socket, read, write)` will be called when a socket changes
    /// state:
    ///
    /// -  `read` is set to true if the socket should listen for read events
    /// -  `write` is set to true if the socket should listen to write events.
    pub fn new<F>(callback: F) -> Result<Channel, AresError>
        where F: FnMut(io::RawFd, bool, bool) + 'static {
        let lib_rc = unsafe {
            c_ares_sys::ares_library_init(c_ares_sys::ARES_LIB_INIT_ALL)
        };
        if lib_rc != c_ares_sys::ARES_SUCCESS {
            return Err(ares_error(lib_rc))
        }

        // TODO suport user-provided options
        let mut ares_channel = ptr::null_mut();
        let mut options = c_ares_sys::Struct_ares_options::default();
        options.flags = c_ares_sys::ARES_FLAG_STAYOPEN;
        options.timeout = 500;
        options.tries = 3;
        options.sock_state_cb = Some(socket_callback::<F>);
        options.sock_state_cb_data = unsafe { mem::transmute(Box::new(callback)) };
        let optmask =
            c_ares_sys::ARES_OPT_FLAGS |
            c_ares_sys::ARES_OPT_TIMEOUTMS |
            c_ares_sys::ARES_OPT_TRIES |
            c_ares_sys::ARES_OPT_SOCK_STATE_CB;
        let channel_rc = unsafe {
            c_ares_sys::ares_init_options(&mut ares_channel, &mut options, optmask)
        };
        if channel_rc != c_ares_sys::ARES_SUCCESS {
            unsafe { c_ares_sys::ares_library_cleanup(); }
            return Err(ares_error(channel_rc))
        }

        let channel = Channel {
            ares_channel: ares_channel,
        };

        // TODO ares_set_servers() here too?
        Ok(channel)
    }

    /// Handle input, output, and timeout events associated with the specified
    /// file descriptors (sockets).
    ///
    /// Providing a value for `read_fd` indicates that the identified socket
    /// is readable; likewise providing a value for `write_fd` indicates that
    /// the identified socket is writable.  Use `INVALID_FD` for "no-action".
    pub fn process_fd(&mut self, read_fd: io::RawFd, write_fd: io::RawFd) {
        unsafe {
            c_ares_sys::ares_process_fd(
                self.ares_channel,
                read_fd as c_ares_sys::ares_socket_t,
                write_fd as c_ares_sys::ares_socket_t);
        }
    }

    /// Look up the A record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_a<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::A as libc::c_int,
                Some(query_a_callback::<F>),
                c_arg);
        }
    }

    /// Look up the AAAA record associated with `name`.
    ///
    /// On completion, `handler` is called with the result.
    pub fn query_aaaa<F>(&mut self, name: &str, handler: F)
        where F: FnOnce(Result<AAAAResult, AresError>) + 'static {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let c_arg: *mut libc::c_void = mem::transmute(Box::new(handler));
            c_ares_sys::ares_query(
                self.ares_channel,
                c_name.as_ptr(),
                DnsClass::IN as libc::c_int,
                QueryType::AAAA as libc::c_int,
                Some(query_aaaa_callback::<F>),
                c_arg);
        }
    }
}

impl Drop for Channel {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_destroy(self.ares_channel);
            c_ares_sys::ares_library_cleanup();
        }
    }
}

unsafe impl Send for Channel { }
<|endoftext|>


<commit_before>#![allow(experimental)]

use std::io::{File,fs};
use std::io::process::Command;
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;
use std::finally::Finally;

static TEMPLATE: &'static str = include_str!("creator/template.yml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
      Path::new(format!("{}/.{}/", homedir_string(), &DEFAULT_MUXED_DIR.to_string()))
    } else {
      create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
      create_project_file(path)
    } else {
      println!("Project already exists.");
    }
}

fn create_project_file(path: &Path) {
    File::create(path);
//    Command::new("vim").arg(format!("{}", path.display())).detached();
}

fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        fs::unlink(path);
    })
}
<commit_msg>Write the file template to the new project file.<commit_after>#![allow(experimental)]

use std::io::{File,fs};
use std::io::process::Command;
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;
use std::finally::Finally;

static TEMPLATE: &'static str = include_str!("creator/template.yml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
      Path::new(format!("{}/.{}/", homedir_string(), &DEFAULT_MUXED_DIR.to_string()))
    } else {
      create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
      create_project_file(path)
    } else {
      println!("Project already exists.");
    }
}

fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (), // succeeded
        Err(e) => println!("failed to write to my diary: {}", e),
    }
//    Command::new("vim").arg(format!("{}", path.display())).detached();
}

fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = format!("test_project_{}", random::<f64>());
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        fs::unlink(path);
    })
}
<|endoftext|>