<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Kashyap
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use super::spinlock::Spinlock;
use super::spinlock::dummy_lock;
use super::spinlock::init_lock;
use super::uart::uart_put_str;
use super::mmu::Address;
use super::mmu::pg_roundup;
use super::mmu::PG_SIZE;

struct kmem_t{
lock: Spinlock,
use_lock: u32 , //TODO is u32 the right type?
	    // TODO  struct run *freelist;
}

static mut kmem : kmem_t = kmem_t { lock: dummy_lock, use_lock: 0} ;

pub fn kinit1(vstart: Address, vend: Address) {
	unsafe {
		init_lock(& mut kmem.lock, "kmem");
		kmem.use_lock = 0;
	}
	free_range(vstart, vend);
}

fn free_range(vstart: Address, vend: Address) {
	let mut address = pg_roundup(vstart);

	// Keep it around for future debugging
	unsafe {
		asm!("mov $0 , %rax" : /* no outputs */ : "r"(vend) : "eax");
		asm!("mov $0 , %rbx" : /* no outputs */ : "r"(address) : "eax");
	}

	loop {
		kfree(address);
		address = address + PG_SIZE;
		if address > vend {
			break;
		}
	}
}

fn kfree(a : Address){
/*
	struct run *r;

	if((uintp)v % PGSIZE || v < end || v2p(v) >= PHYSTOP)
		panic("kfree");

	// Fill with junk to catch dangling refs.
	memset(v, 1, PGSIZE);

	if(kmem.use_lock)
		acquire(&kmem.lock);
	r = (struct run*)v;
	r->next = kmem.freelist;
	kmem.freelist = r;
	if(kmem.use_lock)
		release(&kmem.lock);

		*/
}
<commit_msg>commented out unnecessary code<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Kashyap
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use super::spinlock::Spinlock;
use super::spinlock::dummy_lock;
use super::spinlock::init_lock;
use super::uart::uart_put_str;
use super::mmu::Address;
use super::mmu::pg_roundup;
use super::mmu::PG_SIZE;

struct kmem_t{
lock: Spinlock,
use_lock: u32 , //TODO is u32 the right type?
	    // TODO  struct run *freelist;
}

static mut kmem : kmem_t = kmem_t { lock: dummy_lock, use_lock: 0} ;

pub fn kinit1(vstart: Address, vend: Address) {
	unsafe {
		init_lock(& mut kmem.lock, "kmem");
		kmem.use_lock = 0;
	}
	free_range(vstart, vend);
}

fn free_range(vstart: Address, vend: Address) {
	let mut address = pg_roundup(vstart);

	// Keep it around for future debugging
	//unsafe {
	//	asm!("mov $0 , %rax" : /* no outputs */ : "r"(vend) : "eax");
	//	asm!("mov $0 , %rbx" : /* no outputs */ : "r"(address) : "eax");
	//}

	loop {
		kfree(address);
		address = address + PG_SIZE;
		if address > vend {
			break;
		}
	}
}

fn kfree(a : Address){
/*
	struct run *r;

	if((uintp)v % PGSIZE || v < end || v2p(v) >= PHYSTOP)
		panic("kfree");

	// Fill with junk to catch dangling refs.
	memset(v, 1, PGSIZE);

	if(kmem.use_lock)
		acquire(&kmem.lock);
	r = (struct run*)v;
	r->next = kmem.freelist;
	kmem.freelist = r;
	if(kmem.use_lock)
		release(&kmem.lock);

		*/
}
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * kit/kernel/kernel.rs
 *
 * vim:ft=rust:ts=4:sw=4:et:tw=80
 *
 * Copyright (C) 2015-2021, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 * Based on OSDev Bare Bones tutorial
 * http://wiki.osdev.org/Bare_Bones
 *
 ******************************************************************************/

//! The Kit kernel.

#![crate_name="kernel"]
#![crate_type="lib"]

#![feature(lang_items, asm, box_syntax, alloc_error_handler)]
#![feature(box_patterns, panic_info_message)]
#![feature(repr_simd, const_panic, inline_const)]
#![feature(maybe_uninit_slice, vec_spare_capacity)]

#![allow(improper_ctypes)]

#![cfg_attr(not(test), no_std)]

// These rust libs are specifically configured for Kit.
#[macro_use] extern crate alloc;
#[macro_use] extern crate static_assertions;
#[macro_use] extern crate log as log_crate;

#[cfg(not(test))]
use core::panic::PanicInfo;

#[macro_use] pub mod sync;
#[macro_use] pub mod util;

pub mod log;
pub mod cmdline;
pub mod serial;
pub mod terminal;
pub mod framebuffer;
pub mod constants;
pub mod cpu;
pub mod multiboot;
pub mod memory;
pub mod interrupt;
pub mod paging;
pub mod keyboard;
pub mod archive;
pub mod process;
pub mod elf;
pub mod scheduler;
pub mod syscall;
pub mod c_ffi;
pub mod error;
pub mod ptr;

use terminal::*;
use cmdline::Cmdline;
use memory::InitMemoryMap;

use alloc::string::String;

/// Main kernel entry point.
#[no_mangle]
pub extern fn kernel_main() -> ! {

    let mb_info = unsafe { multiboot::get_info() };

    let cmdline_utf8 = unsafe { mb_info.cmdline() }
        .map(|cstr| String::from(cstr))
        .unwrap_or("".into());

    let cmdline = Cmdline::new(&cmdline_utf8);

    serial::com1().initialize().unwrap();

    log::initialize(&cmdline);

    info!("BOOT: Hello, I'm Kit.");

    debug!("Kernel command line: {}", cmdline);
    debug!("Multiboot info: {:08X?}", mb_info);

    let mut init_memory_map = InitMemoryMap::default();

    if mb_info.flags & multiboot::info_flags::MEM_MAP != 0 {
        unsafe {
            init_memory_map.load_from_multiboot(&mb_info);
        }
    } else {
        panic!("Bootloader did not provide memory map!");
    }

    unsafe {
        memory::initialize(&init_memory_map);
        interrupt::initialize();
        paging::initialize(&init_memory_map);
        terminal::initialize(&mb_info);
    }

    console().reset().unwrap();
    console().set_color(Color::Red, Color::White).unwrap();

    console().write_str("+ Hello, I'm Kit.\n").unwrap();

    console().set_color(Color::White, Color::Red).unwrap();
    console().write_char('\n').unwrap();

    match mb_info.mem_sizes() {
        Some((lower, upper)) => {
            write!(console(),
                   "{:<20} {:<10} KiB\n\
                    {:<20} {:<10} KiB\n",
                   "Lower memory:", lower,
                   "Upper memory:", upper).unwrap();
        },
        None => {
            write!(console(),
                   "W: Bootloader did not provide valid memory information!")
                .unwrap();
        }
    }

    write!(console(), "{:<20} {}\n", "Kernel command line:", cmdline).unwrap();

    console().write_char('\n').unwrap();
    console().set_color(Color::LightGrey, Color::Black).unwrap();
    console().write_char('\n').unwrap();

    unsafe {
        memory::enable_large_heap();
    }

    // We have to wait until enable_large_heap() is called before we can
    // allocate the shadow buffer.
    console().set_double_buffer(true);

    unsafe {
        keyboard::initialize().unwrap();
    }

    if mb_info.flags & multiboot::info_flags::MODS != 0 {
        unsafe {
            let mods = constants::translate_low_addr(mb_info.mods_addr)
                .expect("mods pointer outside low region");

            if !archive::initialize(mods, mb_info.mods_count) {
                panic!("Archive initialization failed. Are you sure \
                        system.kit was provided?");
            }
        }
    } else {
        panic!("Bootloader did not provide modules!");
    }

    unsafe {
        process::initialize();
    }

    let pid;

    {
        let init = cmdline.iter().find(|(key, _)| *key == "init")
            .map(|(_, value)| value);

        if let Some(init) = init {
            let init_cstring = c_ffi::cstring_from_str(init);

            pid = archive::utils::spawn(
                c_ffi::CStr::new(&init_cstring), &[&init_cstring]).unwrap();

            process::wait(pid).unwrap();
        } else {
            panic!("No initial program specified on kernel command line!");
        }
    }

    // In case init exits
    {
        let process = process::by_id(pid).unwrap();

        let name = process.lock().name();
        let exit_status = process.lock().exit_status();

        panic!("Initial process ({}:{}) exited with code {}",
            pid, name, exit_status.unwrap());
    }
}

#[cfg(not(test))]
#[panic_handler]
fn panic_handler(panic_info: &PanicInfo) -> ! {
    error!("Kernel panic: {}", panic_info);

    let _ = console().set_color(Color::White, Color::Red);

    let _ = write!(console(), "\nKernel panic");

    if let Some(location) = panic_info.location() {
        let _ = write!(console(), " in {}", location);
    }

    if let Some(message) = panic_info.message() {
        let _ = write!(console(), ": {}", message);
    }

    unsafe {
        loop { asm!("cli; hlt"); }
    }
}
<commit_msg>option to disable serial initialization<commit_after>/*******************************************************************************
 *
 * kit/kernel/kernel.rs
 *
 * vim:ft=rust:ts=4:sw=4:et:tw=80
 *
 * Copyright (C) 2015-2021, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 * Based on OSDev Bare Bones tutorial
 * http://wiki.osdev.org/Bare_Bones
 *
 ******************************************************************************/

//! The Kit kernel.

#![crate_name="kernel"]
#![crate_type="lib"]

#![feature(lang_items, asm, box_syntax, alloc_error_handler)]
#![feature(box_patterns, panic_info_message)]
#![feature(repr_simd, const_panic, inline_const)]
#![feature(maybe_uninit_slice, vec_spare_capacity)]

#![allow(improper_ctypes)]

#![cfg_attr(not(test), no_std)]

// These rust libs are specifically configured for Kit.
#[macro_use] extern crate alloc;
#[macro_use] extern crate static_assertions;
#[macro_use] extern crate log as log_crate;

#[cfg(not(test))]
use core::panic::PanicInfo;

#[macro_use] pub mod sync;
#[macro_use] pub mod util;

pub mod log;
pub mod cmdline;
pub mod serial;
pub mod terminal;
pub mod framebuffer;
pub mod constants;
pub mod cpu;
pub mod multiboot;
pub mod memory;
pub mod interrupt;
pub mod paging;
pub mod keyboard;
pub mod archive;
pub mod process;
pub mod elf;
pub mod scheduler;
pub mod syscall;
pub mod c_ffi;
pub mod error;
pub mod ptr;

use terminal::*;
use cmdline::Cmdline;
use memory::InitMemoryMap;

use alloc::string::String;

/// Main kernel entry point.
#[no_mangle]
pub extern fn kernel_main() -> ! {

    let mb_info = unsafe { multiboot::get_info() };

    let cmdline_utf8 = unsafe { mb_info.cmdline() }
        .map(|cstr| String::from(cstr))
        .unwrap_or("".into());

    let cmdline = Cmdline::new(&cmdline_utf8);

    if !cmdline.iter().any(|p| p == ("serial", "disable")) {
        serial::com1().initialize().unwrap();
    }

    log::initialize(&cmdline);

    info!("BOOT: Hello, I'm Kit.");

    debug!("Kernel command line: {}", cmdline);
    debug!("Multiboot info: {:08X?}", mb_info);

    let mut init_memory_map = InitMemoryMap::default();

    if mb_info.flags & multiboot::info_flags::MEM_MAP != 0 {
        unsafe {
            init_memory_map.load_from_multiboot(&mb_info);
        }
    } else {
        panic!("Bootloader did not provide memory map!");
    }

    unsafe {
        memory::initialize(&init_memory_map);
        interrupt::initialize();
        paging::initialize(&init_memory_map);
        terminal::initialize(&mb_info);
    }

    console().reset().unwrap();
    console().set_color(Color::Red, Color::White).unwrap();

    console().write_str("+ Hello, I'm Kit.\n").unwrap();

    console().set_color(Color::White, Color::Red).unwrap();
    console().write_char('\n').unwrap();

    match mb_info.mem_sizes() {
        Some((lower, upper)) => {
            write!(console(),
                   "{:<20} {:<10} KiB\n\
                    {:<20} {:<10} KiB\n",
                   "Lower memory:", lower,
                   "Upper memory:", upper).unwrap();
        },
        None => {
            write!(console(),
                   "W: Bootloader did not provide valid memory information!")
                .unwrap();
        }
    }

    write!(console(), "{:<20} {}\n", "Kernel command line:", cmdline).unwrap();

    console().write_char('\n').unwrap();
    console().set_color(Color::LightGrey, Color::Black).unwrap();
    console().write_char('\n').unwrap();

    unsafe {
        memory::enable_large_heap();
    }

    // We have to wait until enable_large_heap() is called before we can
    // allocate the shadow buffer.
    console().set_double_buffer(true);

    unsafe {
        keyboard::initialize().unwrap();
    }

    if mb_info.flags & multiboot::info_flags::MODS != 0 {
        unsafe {
            let mods = constants::translate_low_addr(mb_info.mods_addr)
                .expect("mods pointer outside low region");

            if !archive::initialize(mods, mb_info.mods_count) {
                panic!("Archive initialization failed. Are you sure \
                        system.kit was provided?");
            }
        }
    } else {
        panic!("Bootloader did not provide modules!");
    }

    unsafe {
        process::initialize();
    }

    let pid;

    {
        let init = cmdline.iter().find(|(key, _)| *key == "init")
            .map(|(_, value)| value);

        if let Some(init) = init {
            let init_cstring = c_ffi::cstring_from_str(init);

            pid = archive::utils::spawn(
                c_ffi::CStr::new(&init_cstring), &[&init_cstring]).unwrap();

            process::wait(pid).unwrap();
        } else {
            panic!("No initial program specified on kernel command line!");
        }
    }

    // In case init exits
    {
        let process = process::by_id(pid).unwrap();

        let name = process.lock().name();
        let exit_status = process.lock().exit_status();

        panic!("Initial process ({}:{}) exited with code {}",
            pid, name, exit_status.unwrap());
    }
}

#[cfg(not(test))]
#[panic_handler]
fn panic_handler(panic_info: &PanicInfo) -> ! {
    error!("Kernel panic: {}", panic_info);

    let _ = console().set_color(Color::White, Color::Red);

    let _ = write!(console(), "\nKernel panic");

    if let Some(location) = panic_info.location() {
        let _ = write!(console(), " in {}", location);
    }

    if let Some(message) = panic_info.message() {
        let _ = write!(console(), ": {}", message);
    }

    unsafe {
        loop { asm!("cli; hlt"); }
    }
}
<|endoftext|>


<commit_before>use proc_macro2::{Ident, TokenStream};
use shared::{map_lifetimes, map_type_params, split_for_impl};
use syn::{
    self, Attribute, Data, DeriveInput, Generics, Lit, Meta, MetaList, MetaNameValue, NestedMeta,
};

pub fn derive(input: TokenStream) -> TokenStream {
    let DeriveInput {
        ident,
        attrs,
        data,
        generics,
        ..
    } = syn::parse2(input).expect("Input is checked by rustc");

    let tokens = match data {
        Data::Struct(_) | Data::Enum(_) => gen_impl(ident, generics, &parse_attrs(&attrs)),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn parse_attrs(attrs: &[Attribute]) -> String {
    let ty = attrs
        .iter()
        .filter_map(|attr| {
            attr.interpret_meta().and_then(|meta| {
                // all attrs are namespaced under the gluon attr
                let nested = match meta {
                    Meta::List(MetaList {
                        ref ident,
                        ref nested,
                        ..
                    }) if ident == "gluon" =>
                    {
                        Some(nested)
                    }
                    _ => None,
                }?;

                // find a literal for the vm_type key, ignore other values as they may be required
                // by other macros
                let lit = nested
                    .iter()
                    .filter_map(|meta| match meta {
                        NestedMeta::Meta(Meta::NameValue(MetaNameValue { ident, lit, .. }))
                            if ident == "vm_type" =>
                        {
                            Some(lit)
                        }
                        _ => None,
                    })
                    .next()?;

                match lit {
                    Lit::Str(ty) => Some(ty.value()),
                    _ => panic!("The gluon type name must be a string literal"),
                }
            })
        })
        .next();

    match ty {
        Some(ty) => ty,
        None => panic!("Did not find the gluon type this type will be mapped to. Specify it with #[gluon(vm_type = \"<gluon_type>\")]"),
    }
}

fn gen_impl(ident: Ident, generics: Generics, gluon_type: &str) -> TokenStream {
    let trait_bounds = &map_type_params(&generics, |ty| {
        quote! { #ty: 'static + ::gluon::vm::api::VmType }
    });

    let lifetime_bounds = &map_lifetimes(&generics, |lifetime| quote! { #lifetime: 'static });

    let type_application = gen_type_application(&generics);
    let (impl_generics, ty_generics, where_clause) = split_for_impl(&generics, &[]);

    quote! {
        impl #impl_generics ::gluon::vm::api::VmType for #ident #ty_generics
        #where_clause #(#trait_bounds,)* #(#lifetime_bounds),*
        {
            type Type = Self;

            fn make_type(vm: &::gluon::vm::thread::Thread) -> ::gluon::base::types::ArcType {
                let env = <::gluon::vm::thread::Thread as ::gluon::vm::thread::ThreadInternal>::global_env(
                    vm,
                ).get_env();

                let info = env.find_type_info(#gluon_type);

                let ty = match info {
                    Ok(info) => info.into_owned().into_type(),
                    Err(_) => panic!("Could not find type '{}'. Is the module defining the type loaded?", #gluon_type),
                };

                #type_application
            }
        }
    }
}

fn gen_type_application(generics: &Generics) -> TokenStream {
    let applications = map_type_params(generics, |param| {
        quote! {
            vec.push(<#param as ::gluon::vm::api::VmType>::make_type(vm));
        }
    });

    // if there are generic parameters, we use their types and apply them
    // to the type of the derive target to construct the concrete type
    if applications.is_empty() {
        quote! {
            ty
        }
    } else {
        quote! {
            let mut vec = ::gluon::base::types::AppVec::new();
            #(#applications)*
            ::gluon::base::types::Type::app(ty, vec)
        }
    }
}
<commit_msg>Use Thread::find_type_info for getting the gluon type<commit_after>use proc_macro2::{Ident, TokenStream};
use shared::{map_lifetimes, map_type_params, split_for_impl};
use syn::{
    self, Attribute, Data, DeriveInput, Generics, Lit, Meta, MetaList, MetaNameValue, NestedMeta,
};

pub fn derive(input: TokenStream) -> TokenStream {
    let DeriveInput {
        ident,
        attrs,
        data,
        generics,
        ..
    } = syn::parse2(input).expect("Input is checked by rustc");

    let tokens = match data {
        Data::Struct(_) | Data::Enum(_) => gen_impl(ident, generics, &parse_attrs(&attrs)),
        Data::Union(_) => panic!("Unions are not supported"),
    };

    tokens.into()
}

fn parse_attrs(attrs: &[Attribute]) -> String {
    let ty = attrs
        .iter()
        .filter_map(|attr| {
            attr.interpret_meta().and_then(|meta| {
                // all attrs are namespaced under the gluon attr
                let nested = match meta {
                    Meta::List(MetaList {
                        ref ident,
                        ref nested,
                        ..
                    }) if ident == "gluon" =>
                    {
                        Some(nested)
                    }
                    _ => None,
                }?;

                // find a literal for the vm_type key, ignore other values as they may be required
                // by other macros
                let lit = nested
                    .iter()
                    .filter_map(|meta| match meta {
                        NestedMeta::Meta(Meta::NameValue(MetaNameValue { ident, lit, .. }))
                            if ident == "vm_type" =>
                        {
                            Some(lit)
                        }
                        _ => None,
                    })
                    .next()?;

                match lit {
                    Lit::Str(ty) => Some(ty.value()),
                    _ => panic!("The gluon type name must be a string literal"),
                }
            })
        })
        .next();

    match ty {
        Some(ty) => ty,
        None => panic!("Did not find the gluon type this type will be mapped to. Specify it with #[gluon(vm_type = \"<gluon_type>\")]"),
    }
}

fn gen_impl(ident: Ident, generics: Generics, gluon_type: &str) -> TokenStream {
    let trait_bounds = &map_type_params(&generics, |ty| {
        quote! { #ty: 'static + ::gluon::vm::api::VmType }
    });

    let lifetime_bounds = &map_lifetimes(&generics, |lifetime| quote! { #lifetime: 'static });

    let type_application = gen_type_application(&generics);
    let (impl_generics, ty_generics, where_clause) = split_for_impl(&generics, &[]);

    quote! {
        impl #impl_generics ::gluon::vm::api::VmType for #ident #ty_generics
        #where_clause #(#trait_bounds,)* #(#lifetime_bounds),*
        {
            type Type = Self;

            fn make_type(vm: &::gluon::vm::thread::Thread) -> ::gluon::base::types::ArcType {
                let ty = match vm.find_type_info(#gluon_type) {
                    Ok(info) => info.into_type(),
                    Err(_) => panic!("Could not find type '{}'. Is the module defining the type loaded?", #gluon_type),
                };

                #type_application
            }
        }
    }
}

fn gen_type_application(generics: &Generics) -> TokenStream {
    let applications = map_type_params(generics, |param| {
        quote! {
            vec.push(<#param as ::gluon::vm::api::VmType>::make_type(vm));
        }
    });

    // if there are generic parameters, we use their types and apply them
    // to the type of the derive target to construct the concrete type
    if applications.is_empty() {
        quote! {
            ty
        }
    } else {
        quote! {
            let mut vec = ::gluon::base::types::AppVec::new();
            #(#applications)*
            ::gluon::base::types::Type::app(ty, vec)
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [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, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    keys:   [u8; 16],
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            keys:   [0; 16],
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp  = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn dec_pc(&mut self) {
        self.pc -= 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;

        // TODO: I guess this shouldn't be this way
        let res = self.regs[idx_x]  as u16 + self.inst.kk as u16;

        if res > 0xFF {
            self.regs[idx_x] = (res & 0xFF) as u8;
        } else {
            self.regs[idx_x] += self.inst.kk;
        }
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx] as u16;
        self.regs[15] = if (self.i + x) > 0xFFF { 1 } else { 0 };
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };

        if x <= y { self.regs[idx_x] = 0; }
        else { self.regs[idx_x] -= y; }
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let x     = self.regs[idx_x];
        self.regs[15] = x & 0x1;
        self.regs[idx_x] = x >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx];

        self.mem[self.i as usize]     = x / 100;
        self.mem[self.i as usize + 1] = (x / 100) % 10;
        self.mem[self.i as usize + 2] = (x % 100) % 10;
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        for i in 0..self.keys.len() {
            if self.keys[i] == 1 {
                self.regs[self.inst.x] = i as u8;
                key_pressed = true;
            }
        }

        if !key_pressed {
            self.dec_pc();
        }
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        self.screen.renderer.clear();
        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(self.i + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..32*10 {
            for j in 0usize..64*10 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }

        self.screen.draw();
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 1{
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 0 {
            self.inc_pc();
        }
    }
    pub fn reset_keys(&mut self) {
        self.keys = [0;16];
    }

    pub fn press(&mut self, key: u8) {
        self.keys[key as usize] = 1;
    }
}
<commit_msg>added SUBN instruction<commit_after>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [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, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    keys:   [u8; 16],
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            keys:   [0; 16],
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp  = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::SUBN   => self.subn(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn dec_pc(&mut self) {
        self.pc -= 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;

        // TODO: I guess this shouldn't be this way
        let res = self.regs[idx_x]  as u16 + self.inst.kk as u16;

        if res > 0xFF {
            self.regs[idx_x] = (res & 0xFF) as u8;
        } else {
            self.regs[idx_x] += self.inst.kk;
        }
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx] as u16;
        self.regs[15] = if (self.i + x) > 0xFFF { 1 } else { 0 };
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[0xF] = (x > y) as u8;

        if x <= y { self.regs[idx_x] = 0; }
        else { self.regs[idx_x] -= y; }
    }

    fn subn(&mut self) {
        let x = self.regs[self.inst.x];
        let y = self.regs[self.inst.y];

        self.regs[0xF] = (y > x) as u8;
        self.regs[self.inst.x] = y - x;
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let x     = self.regs[idx_x];
        self.regs[15] = x & 0x1;
        self.regs[idx_x] = x >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx];

        self.mem[self.i as usize]     = x / 100;
        self.mem[self.i as usize + 1] = (x / 100) % 10;
        self.mem[self.i as usize + 2] = (x % 100) % 10;
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        for i in 0..self.keys.len() {
            if self.keys[i] == 1 {
                self.regs[self.inst.x] = i as u8;
                key_pressed = true;
            }
        }

        if !key_pressed {
            self.dec_pc();
        }
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        self.screen.renderer.clear();
        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(self.i + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..32*10 {
            for j in 0usize..64*10 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }

        self.screen.draw();
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 1{
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 0 {
            self.inc_pc();
        }
    }
    pub fn reset_keys(&mut self) {
        self.keys = [0;16];
    }

    pub fn press(&mut self, key: u8) {
        self.keys[key as usize] = 1;
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib::translate::*;
use std::clone::Clone;
use std::cmp::PartialEq;
use std::ops::Drop;
use std::ptr;
use ffi;

pub use ffi::enums::{
    Antialias,
    SubpixelOrder,
    HintStyle,
    HintMetrics,

    FontType,
    FontWeight,
    FontSlant,
    TextClusterFlags,
};
use ::matrices::{
    Matrix,
    MatrixTrait
};
use ffi::{
    cairo_font_options_t,
    cairo_font_face_t,
    cairo_scaled_font_t
};

pub use ffi::{
    FontExtents,
    Glyph,
    TextCluster,
    TextExtents
};

/* TODO
 Allocates an array of cairo_glyph_t's. This function is only useful in
 implementations of cairo_user_scaled_font_text_to_glyphs_func_t where the user
 needs to allocate an array of glyphs that cairo will free. For all other uses,
 user can use their own allocation method for glyphs.

impl Glyph {

    //pub fn cairo_glyph_allocate(num_glyphs: c_int) -> *Glyph;

    //pub fn cairo_glyph_free(glyphs: *Glyph);
}

 Allocates an array of cairo_glyph_t's. This function is only useful in
 implementations of cairo_user_scaled_font_text_to_glyphs_func_t where the user
 needs to allocate an array of glyphs that cairo will free. For all other uses,
 user can use their own allocation method for glyphs.

impl TextCluster {
    //pub fn cairo_text_cluster_allocate(num_clusters: c_int) -> *TextCluster;

    //pub fn cairo_text_cluster_free(clusters: *TextCluster);
}
*/

pub struct FontOptions(*mut cairo_font_options_t);

impl FontOptions {
    pub fn new() -> FontOptions {
        let font_options = unsafe {
            FontOptions(ffi::cairo_font_options_create())
        };
        font_options.ensure_status();
        font_options
    }

    #[doc(hidden)]
    pub fn get_ptr(&self) -> *mut cairo_font_options_t {
        let FontOptions(ptr) = *self;
        ptr
    }

    pub fn ensure_status(&self) {
        let status = unsafe {
            ffi::cairo_font_options_status(self.get_ptr())
        };
        status.ensure_valid()
    }

    pub fn merge(&mut self, other: &mut FontOptions) {
        unsafe {
            ffi::cairo_font_options_merge(self.get_ptr(), other.get_ptr())
        }
    }

    pub fn hash(&self) -> u64{
        unsafe {
            ffi::cairo_font_options_hash(self.get_ptr()) as u64
        }
    }

    pub fn set_antialias(&self, antialias: Antialias) {
        unsafe {
            ffi::cairo_font_options_set_antialias(self.get_ptr(), antialias)
        }
    }

    pub fn get_antialias(&self) -> Antialias {
        unsafe {
            ffi::cairo_font_options_get_antialias(self.get_ptr())
        }
    }

    pub fn set_subpixel_order(&self, order: SubpixelOrder) {
        unsafe {
            ffi::cairo_font_options_set_subpixel_order(self.get_ptr(), order)
        }
    }

    pub fn get_subpixel_order(&self) -> SubpixelOrder {
        unsafe {
            ffi::cairo_font_options_get_subpixel_order(self.get_ptr())
        }
    }

    pub fn set_hint_style(&self, hint_style: HintStyle) {
        unsafe {
            ffi::cairo_font_options_set_hint_style(self.get_ptr(), hint_style)
        }
    }

    pub fn get_hint_style(&self) -> HintStyle {
        unsafe {
            ffi::cairo_font_options_get_hint_style(self.get_ptr())
        }
    }

    pub fn set_hint_metrics(&self, hint_metrics: HintMetrics) {
        unsafe {
            ffi::cairo_font_options_set_hint_metrics(self.get_ptr(), hint_metrics)
        }
    }

    pub fn get_hint_metrics(&self) -> HintMetrics {
        unsafe {
            ffi::cairo_font_options_get_hint_metrics(self.get_ptr())
        }
    }
}

impl<'a> ToGlibPtr<'a, *const cairo_font_options_t> for &'a FontOptions {
    type Storage = &'a FontOptions;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *const cairo_font_options_t, &'a FontOptions> {
        Stash(self.0, *self)
    }
}

impl FromGlibPtrNone<*const cairo_font_options_t> for FontOptions {
    #[inline]
    unsafe fn from_glib_none(ptr: *const cairo_font_options_t) -> Self {
        let tmp = ffi::cairo_font_options_copy(ptr);
        assert!(!tmp.is_null());
        FontOptions(tmp)
    }
}

impl PartialEq for FontOptions {
    fn eq(&self, other: &FontOptions) -> bool {
        unsafe {
            ffi::cairo_font_options_equal(self.get_ptr(), other.get_ptr()).as_bool()
        }
    }
}

impl Clone for FontOptions {
    fn clone(&self) -> FontOptions {
        unsafe {
            FontOptions(ffi::cairo_font_options_copy(self.get_ptr()))
        }
    }
}

impl Drop for FontOptions {
    fn drop(&mut self) {
        unsafe {
            ffi::cairo_font_options_destroy(self.get_ptr())
        }
    }
}

pub struct FontFace(*mut cairo_font_face_t);

impl FontFace {
    #[doc(hidden)]
    pub fn get_ptr(&self) -> *mut cairo_font_face_t {
        let FontFace(ptr) = *self;
        ptr
    }

    pub fn toy_create(family: &str, slant: FontSlant, weight: FontWeight) -> FontFace {
        let font_face = FontFace(
            unsafe {
                ffi::cairo_toy_font_face_create(family.to_glib_none().0, slant, weight)
            }
        );
        font_face.ensure_status();
        font_face
    }

    pub fn toy_get_family(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::cairo_toy_font_face_get_family(self.get_ptr()))
        }
    }

    pub fn toy_get_slant(&self) -> FontSlant {
        unsafe {
            ffi::cairo_toy_font_face_get_slant(self.get_ptr())
        }
    }

    pub fn toy_get_weight(&self) -> FontWeight {
        unsafe {
            ffi::cairo_toy_font_face_get_weight(self.get_ptr())
        }
    }

    pub fn ensure_status(&self) {
        let status = unsafe {
            ffi::cairo_font_face_status(self.get_ptr())
        };
        status.ensure_valid()
    }

    pub fn get_type(&self) -> FontType {
        unsafe {
            ffi::cairo_font_face_get_type(self.get_ptr())
        }
    }

    pub fn get_reference_count(&self) -> usize {
        unsafe {
            ffi::cairo_font_face_get_reference_count(self.get_ptr()) as usize
        }
    }

    pub fn reference(&self) -> FontFace {
        unsafe {
            FontFace(ffi::cairo_font_face_reference(self.get_ptr()))
        }
    }
}

impl<'a> ToGlibPtr<'a, *const cairo_font_face_t> for &'a FontFace {
    type Storage = &'a FontFace;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *const cairo_font_face_t, &'a FontFace> {
        Stash(self.0, *self)
    }
}

impl FromGlibPtrNone<*mut cairo_font_face_t> for FontFace {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut cairo_font_face_t) -> Self {
        let tmp = ffi::cairo_font_face_reference(ptr);
        assert!(!tmp.is_null());
        FontFace(tmp)
    }
}

impl Drop for FontFace {
    fn drop(&mut self) {
        unsafe {
            ffi::cairo_font_face_destroy(self.get_ptr())
        }
    }
}

pub struct ScaledFont(pub *mut cairo_scaled_font_t);

impl ScaledFont {
    #[doc(hidden)]
    pub fn get_ptr(&self) -> *mut cairo_scaled_font_t {
        let ScaledFont(ptr) = *self;
        ptr
    }

    pub fn new(font_face: FontFace, font_matrix: &mut Matrix, ctm: &mut Matrix, options: FontOptions) -> ScaledFont {
        let scaled_font = unsafe {
            ScaledFont(ffi::cairo_scaled_font_create(font_face.get_ptr(), font_matrix, ctm, options.get_ptr()))
        };
        scaled_font.ensure_status();
        scaled_font
    }

    pub fn ensure_status(&self) {
        let status = unsafe {
            ffi::cairo_scaled_font_status(self.get_ptr())
        };
        status.ensure_valid()
    }

    pub fn get_type(&self) -> FontType {
        unsafe {
            ffi::cairo_scaled_font_get_type(self.get_ptr())
        }
    }

    pub fn get_reference_count(&self) -> usize {
        unsafe {
            ffi::cairo_scaled_font_get_reference_count(self.get_ptr()) as usize
        }
    }

    pub fn extents(&self) -> FontExtents {
        let mut extents = FontExtents {
            ascent: 0.0,
            descent: 0.0,
            height: 0.0,
            max_x_advance: 0.0,
            max_y_advance: 0.0,
        };

        unsafe {
            ffi::cairo_scaled_font_extents(self.get_ptr(), &mut extents)
        }

        extents
    }

    pub fn text_extents(&self, text: &str) -> TextExtents {
        let mut extents = TextExtents {
            x_bearing: 0.0,
            y_bearing: 0.0,
            width: 0.0,
            height: 0.0,
            x_advance: 0.0,
            y_advance: 0.0,
        };

        unsafe {
            ffi::cairo_scaled_font_text_extents(self.get_ptr(), text.to_glib_none().0, &mut extents)
        }

        extents
    }

    pub fn glyph_extents(&self, glyphs: &[Glyph]) -> TextExtents {
        let mut extents = TextExtents {
            x_bearing: 0.0,
            y_bearing: 0.0,
            width: 0.0,
            height: 0.0,
            x_advance: 0.0,
            y_advance: 0.0,
        };

        unsafe {
            ffi::cairo_scaled_font_glyph_extents(self.get_ptr(), glyphs.as_ptr(), glyphs.len() as i32, &mut extents)
        }

        extents
    }

    pub fn text_to_glyphs(&self, x: f64, y: f64, text: &str) -> (Vec<Glyph>, Vec<TextCluster>) {
        // This large unsafe block is due to the FFI function returning two specially allocated
        // (cairo_{glyph,text_cluster}_allocate) pointers that need to be copied into Vec<T>
        // types before they're of any use to Rust code.

        unsafe {
            let mut glyphs_ptr: *mut Glyph = ptr::null_mut();
            let mut glyph_count = 0i32;
            let mut clusters_ptr: *mut TextCluster = ptr::null_mut();
            let mut cluster_count = 0i32;
            let mut cluster_flags = TextClusterFlags::None;

            let status = ffi::cairo_scaled_font_text_to_glyphs(
                self.get_ptr(),
                x,
                y,
                text.to_glib_none().0,
                text.len() as i32,
                &mut glyphs_ptr,
                &mut glyph_count,
                &mut clusters_ptr,
                &mut cluster_count,
                &mut cluster_flags);

            status.ensure_valid();

            let glyph_count = glyph_count as usize;
            let glyphs: Vec<Glyph> = {
                let mut glyphs: Vec<Glyph> = Vec::with_capacity(glyph_count);

                glyphs.set_len(glyph_count);
                ptr::copy(glyphs_ptr, glyphs.as_mut_ptr(), glyph_count);

                glyphs
            };

            let cluster_count = cluster_count as usize;
            let clusters: Vec<TextCluster> = {
                let mut clusters = Vec::with_capacity(cluster_count);

                clusters.set_len(cluster_count);
                ptr::copy(clusters_ptr, clusters.as_mut_ptr(), cluster_count);

                clusters
            };

            ffi::cairo_glyph_free(glyphs_ptr);
            ffi::cairo_text_cluster_free(clusters_ptr);

            (glyphs, clusters)
        }
    }

    pub fn get_font_face(&self) -> FontFace {
        unsafe {
            FontFace(ffi::cairo_scaled_font_get_font_face(self.get_ptr()))
        }
    }

    pub fn get_font_options(&self) -> FontOptions {
        let options = FontOptions::new();

        unsafe {
            ffi::cairo_scaled_font_get_font_options(self.get_ptr(), options.get_ptr())
        }

        options
    }

    pub fn get_font_matrix(&self) -> Matrix {
        let mut matrix = Matrix::null();

        unsafe {
            ffi::cairo_scaled_font_get_font_matrix(self.get_ptr(), &mut matrix)
        }

        matrix
    }

    pub fn get_ctm(&self) -> Matrix {
        let mut matrix = Matrix::null();

        unsafe {
            ffi::cairo_scaled_font_get_ctm(self.get_ptr(), &mut matrix)
        }

        matrix
    }

    pub fn get_scale_matrix(&self) -> Matrix {
        let mut matrix = Matrix::null();

        unsafe {
            ffi::cairo_scaled_font_get_scale_matrix(self.get_ptr(), &mut matrix)
        }

        matrix
    }

    pub fn reference(&self) -> ScaledFont {
        unsafe {
            ScaledFont(ffi::cairo_scaled_font_reference(self.get_ptr()))
        }
    }
}

impl Drop for ScaledFont {
    fn drop(&mut self) {
        unsafe {
            ffi::cairo_scaled_font_destroy(self.get_ptr())
        }
    }
}
<commit_msg>impl FromGlibPtrFull for Font{Options,Face}<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib::translate::*;
use std::clone::Clone;
use std::cmp::PartialEq;
use std::ops::Drop;
use std::ptr;
use ffi;

pub use ffi::enums::{
    Antialias,
    SubpixelOrder,
    HintStyle,
    HintMetrics,

    FontType,
    FontWeight,
    FontSlant,
    TextClusterFlags,
};
use ::matrices::{
    Matrix,
    MatrixTrait
};
use ffi::{
    cairo_font_options_t,
    cairo_font_face_t,
    cairo_scaled_font_t
};

pub use ffi::{
    FontExtents,
    Glyph,
    TextCluster,
    TextExtents
};

/* TODO
 Allocates an array of cairo_glyph_t's. This function is only useful in
 implementations of cairo_user_scaled_font_text_to_glyphs_func_t where the user
 needs to allocate an array of glyphs that cairo will free. For all other uses,
 user can use their own allocation method for glyphs.

impl Glyph {

    //pub fn cairo_glyph_allocate(num_glyphs: c_int) -> *Glyph;

    //pub fn cairo_glyph_free(glyphs: *Glyph);
}

 Allocates an array of cairo_glyph_t's. This function is only useful in
 implementations of cairo_user_scaled_font_text_to_glyphs_func_t where the user
 needs to allocate an array of glyphs that cairo will free. For all other uses,
 user can use their own allocation method for glyphs.

impl TextCluster {
    //pub fn cairo_text_cluster_allocate(num_clusters: c_int) -> *TextCluster;

    //pub fn cairo_text_cluster_free(clusters: *TextCluster);
}
*/

pub struct FontOptions(*mut cairo_font_options_t);

impl FontOptions {
    pub fn new() -> FontOptions {
        let font_options = unsafe {
            FontOptions(ffi::cairo_font_options_create())
        };
        font_options.ensure_status();
        font_options
    }

    #[doc(hidden)]
    pub fn get_ptr(&self) -> *mut cairo_font_options_t {
        let FontOptions(ptr) = *self;
        ptr
    }

    pub fn ensure_status(&self) {
        let status = unsafe {
            ffi::cairo_font_options_status(self.get_ptr())
        };
        status.ensure_valid()
    }

    pub fn merge(&mut self, other: &mut FontOptions) {
        unsafe {
            ffi::cairo_font_options_merge(self.get_ptr(), other.get_ptr())
        }
    }

    pub fn hash(&self) -> u64{
        unsafe {
            ffi::cairo_font_options_hash(self.get_ptr()) as u64
        }
    }

    pub fn set_antialias(&self, antialias: Antialias) {
        unsafe {
            ffi::cairo_font_options_set_antialias(self.get_ptr(), antialias)
        }
    }

    pub fn get_antialias(&self) -> Antialias {
        unsafe {
            ffi::cairo_font_options_get_antialias(self.get_ptr())
        }
    }

    pub fn set_subpixel_order(&self, order: SubpixelOrder) {
        unsafe {
            ffi::cairo_font_options_set_subpixel_order(self.get_ptr(), order)
        }
    }

    pub fn get_subpixel_order(&self) -> SubpixelOrder {
        unsafe {
            ffi::cairo_font_options_get_subpixel_order(self.get_ptr())
        }
    }

    pub fn set_hint_style(&self, hint_style: HintStyle) {
        unsafe {
            ffi::cairo_font_options_set_hint_style(self.get_ptr(), hint_style)
        }
    }

    pub fn get_hint_style(&self) -> HintStyle {
        unsafe {
            ffi::cairo_font_options_get_hint_style(self.get_ptr())
        }
    }

    pub fn set_hint_metrics(&self, hint_metrics: HintMetrics) {
        unsafe {
            ffi::cairo_font_options_set_hint_metrics(self.get_ptr(), hint_metrics)
        }
    }

    pub fn get_hint_metrics(&self) -> HintMetrics {
        unsafe {
            ffi::cairo_font_options_get_hint_metrics(self.get_ptr())
        }
    }
}

impl<'a> ToGlibPtr<'a, *const cairo_font_options_t> for &'a FontOptions {
    type Storage = &'a FontOptions;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *const cairo_font_options_t, &'a FontOptions> {
        Stash(self.0, *self)
    }
}

impl FromGlibPtrNone<*const cairo_font_options_t> for FontOptions {
    #[inline]
    unsafe fn from_glib_none(ptr: *const cairo_font_options_t) -> Self {
        let tmp = ffi::cairo_font_options_copy(ptr);
        assert!(!tmp.is_null());
        FontOptions(tmp)
    }
}

impl FromGlibPtrFull<*mut cairo_font_options_t> for FontOptions {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut cairo_font_options_t) -> Self {
        assert!(!ptr.is_null());
        FontOptions(ptr)
    }
}

impl PartialEq for FontOptions {
    fn eq(&self, other: &FontOptions) -> bool {
        unsafe {
            ffi::cairo_font_options_equal(self.get_ptr(), other.get_ptr()).as_bool()
        }
    }
}

impl Clone for FontOptions {
    fn clone(&self) -> FontOptions {
        unsafe {
            FontOptions(ffi::cairo_font_options_copy(self.get_ptr()))
        }
    }
}

impl Drop for FontOptions {
    fn drop(&mut self) {
        unsafe {
            ffi::cairo_font_options_destroy(self.get_ptr())
        }
    }
}

pub struct FontFace(*mut cairo_font_face_t);

impl FontFace {
    #[doc(hidden)]
    pub fn get_ptr(&self) -> *mut cairo_font_face_t {
        let FontFace(ptr) = *self;
        ptr
    }

    pub fn toy_create(family: &str, slant: FontSlant, weight: FontWeight) -> FontFace {
        let font_face = FontFace(
            unsafe {
                ffi::cairo_toy_font_face_create(family.to_glib_none().0, slant, weight)
            }
        );
        font_face.ensure_status();
        font_face
    }

    pub fn toy_get_family(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::cairo_toy_font_face_get_family(self.get_ptr()))
        }
    }

    pub fn toy_get_slant(&self) -> FontSlant {
        unsafe {
            ffi::cairo_toy_font_face_get_slant(self.get_ptr())
        }
    }

    pub fn toy_get_weight(&self) -> FontWeight {
        unsafe {
            ffi::cairo_toy_font_face_get_weight(self.get_ptr())
        }
    }

    pub fn ensure_status(&self) {
        let status = unsafe {
            ffi::cairo_font_face_status(self.get_ptr())
        };
        status.ensure_valid()
    }

    pub fn get_type(&self) -> FontType {
        unsafe {
            ffi::cairo_font_face_get_type(self.get_ptr())
        }
    }

    pub fn get_reference_count(&self) -> usize {
        unsafe {
            ffi::cairo_font_face_get_reference_count(self.get_ptr()) as usize
        }
    }

    pub fn reference(&self) -> FontFace {
        unsafe {
            FontFace(ffi::cairo_font_face_reference(self.get_ptr()))
        }
    }
}

impl<'a> ToGlibPtr<'a, *const cairo_font_face_t> for &'a FontFace {
    type Storage = &'a FontFace;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *const cairo_font_face_t, &'a FontFace> {
        Stash(self.0, *self)
    }
}

impl FromGlibPtrNone<*mut cairo_font_face_t> for FontFace {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut cairo_font_face_t) -> Self {
        let tmp = ffi::cairo_font_face_reference(ptr);
        assert!(!tmp.is_null());
        FontFace(tmp)
    }
}

impl FromGlibPtrFull<*mut cairo_font_face_t> for FontFace {
    #[inline]
    unsafe fn from_glib_full(ptr: *mut cairo_font_face_t) -> Self {
        assert!(!ptr.is_null());
        FontFace(ptr)
    }
}

impl Drop for FontFace {
    fn drop(&mut self) {
        unsafe {
            ffi::cairo_font_face_destroy(self.get_ptr())
        }
    }
}

pub struct ScaledFont(pub *mut cairo_scaled_font_t);

impl ScaledFont {
    #[doc(hidden)]
    pub fn get_ptr(&self) -> *mut cairo_scaled_font_t {
        let ScaledFont(ptr) = *self;
        ptr
    }

    pub fn new(font_face: FontFace, font_matrix: &mut Matrix, ctm: &mut Matrix, options: FontOptions) -> ScaledFont {
        let scaled_font = unsafe {
            ScaledFont(ffi::cairo_scaled_font_create(font_face.get_ptr(), font_matrix, ctm, options.get_ptr()))
        };
        scaled_font.ensure_status();
        scaled_font
    }

    pub fn ensure_status(&self) {
        let status = unsafe {
            ffi::cairo_scaled_font_status(self.get_ptr())
        };
        status.ensure_valid()
    }

    pub fn get_type(&self) -> FontType {
        unsafe {
            ffi::cairo_scaled_font_get_type(self.get_ptr())
        }
    }

    pub fn get_reference_count(&self) -> usize {
        unsafe {
            ffi::cairo_scaled_font_get_reference_count(self.get_ptr()) as usize
        }
    }

    pub fn extents(&self) -> FontExtents {
        let mut extents = FontExtents {
            ascent: 0.0,
            descent: 0.0,
            height: 0.0,
            max_x_advance: 0.0,
            max_y_advance: 0.0,
        };

        unsafe {
            ffi::cairo_scaled_font_extents(self.get_ptr(), &mut extents)
        }

        extents
    }

    pub fn text_extents(&self, text: &str) -> TextExtents {
        let mut extents = TextExtents {
            x_bearing: 0.0,
            y_bearing: 0.0,
            width: 0.0,
            height: 0.0,
            x_advance: 0.0,
            y_advance: 0.0,
        };

        unsafe {
            ffi::cairo_scaled_font_text_extents(self.get_ptr(), text.to_glib_none().0, &mut extents)
        }

        extents
    }

    pub fn glyph_extents(&self, glyphs: &[Glyph]) -> TextExtents {
        let mut extents = TextExtents {
            x_bearing: 0.0,
            y_bearing: 0.0,
            width: 0.0,
            height: 0.0,
            x_advance: 0.0,
            y_advance: 0.0,
        };

        unsafe {
            ffi::cairo_scaled_font_glyph_extents(self.get_ptr(), glyphs.as_ptr(), glyphs.len() as i32, &mut extents)
        }

        extents
    }

    pub fn text_to_glyphs(&self, x: f64, y: f64, text: &str) -> (Vec<Glyph>, Vec<TextCluster>) {
        // This large unsafe block is due to the FFI function returning two specially allocated
        // (cairo_{glyph,text_cluster}_allocate) pointers that need to be copied into Vec<T>
        // types before they're of any use to Rust code.

        unsafe {
            let mut glyphs_ptr: *mut Glyph = ptr::null_mut();
            let mut glyph_count = 0i32;
            let mut clusters_ptr: *mut TextCluster = ptr::null_mut();
            let mut cluster_count = 0i32;
            let mut cluster_flags = TextClusterFlags::None;

            let status = ffi::cairo_scaled_font_text_to_glyphs(
                self.get_ptr(),
                x,
                y,
                text.to_glib_none().0,
                text.len() as i32,
                &mut glyphs_ptr,
                &mut glyph_count,
                &mut clusters_ptr,
                &mut cluster_count,
                &mut cluster_flags);

            status.ensure_valid();

            let glyph_count = glyph_count as usize;
            let glyphs: Vec<Glyph> = {
                let mut glyphs: Vec<Glyph> = Vec::with_capacity(glyph_count);

                glyphs.set_len(glyph_count);
                ptr::copy(glyphs_ptr, glyphs.as_mut_ptr(), glyph_count);

                glyphs
            };

            let cluster_count = cluster_count as usize;
            let clusters: Vec<TextCluster> = {
                let mut clusters = Vec::with_capacity(cluster_count);

                clusters.set_len(cluster_count);
                ptr::copy(clusters_ptr, clusters.as_mut_ptr(), cluster_count);

                clusters
            };

            ffi::cairo_glyph_free(glyphs_ptr);
            ffi::cairo_text_cluster_free(clusters_ptr);

            (glyphs, clusters)
        }
    }

    pub fn get_font_face(&self) -> FontFace {
        unsafe {
            FontFace(ffi::cairo_scaled_font_get_font_face(self.get_ptr()))
        }
    }

    pub fn get_font_options(&self) -> FontOptions {
        let options = FontOptions::new();

        unsafe {
            ffi::cairo_scaled_font_get_font_options(self.get_ptr(), options.get_ptr())
        }

        options
    }

    pub fn get_font_matrix(&self) -> Matrix {
        let mut matrix = Matrix::null();

        unsafe {
            ffi::cairo_scaled_font_get_font_matrix(self.get_ptr(), &mut matrix)
        }

        matrix
    }

    pub fn get_ctm(&self) -> Matrix {
        let mut matrix = Matrix::null();

        unsafe {
            ffi::cairo_scaled_font_get_ctm(self.get_ptr(), &mut matrix)
        }

        matrix
    }

    pub fn get_scale_matrix(&self) -> Matrix {
        let mut matrix = Matrix::null();

        unsafe {
            ffi::cairo_scaled_font_get_scale_matrix(self.get_ptr(), &mut matrix)
        }

        matrix
    }

    pub fn reference(&self) -> ScaledFont {
        unsafe {
            ScaledFont(ffi::cairo_scaled_font_reference(self.get_ptr()))
        }
    }
}

impl Drop for ScaledFont {
    fn drop(&mut self) {
        unsafe {
            ffi::cairo_scaled_font_destroy(self.get_ptr())
        }
    }
}
<|endoftext|>


<commit_before>use super::traits::{EdgeWeight, Edges, Graph};
use closed01::Closed01;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use petgraph::{EdgeDirection, Directed};
use petgraph::Graph as PetGraph;
use std::fmt::Debug;

#[derive(Debug)]
pub struct Edge {
    /// Node index type. Our graphs never exceed 4 billion nodes.
    pointing_node: u32,
    weight: EdgeWeight,
}

impl Edge {
    pub fn new_unweighted(node_idx: usize) -> Edge {
        Edge::new(node_idx, Closed01::zero())
    }

    pub fn new(node_idx: usize, weight: EdgeWeight) -> Edge {
        assert!(node_idx <= u32::max_value() as usize);
        Edge {
            pointing_node: node_idx as u32,
            weight: weight,
        }
    }
}

#[derive(Debug)]
pub struct EdgeList {
    edges: Vec<Edge>,
}

impl EdgeList {
    pub fn new(edges: Vec<Edge>) -> EdgeList {
        EdgeList { edges: edges }
    }
}

impl Edges for EdgeList {
    #[inline]
    fn num_edges(&self) -> usize {
        self.edges.len()
    }

    #[inline]
    fn nth_edge(&self, n: usize) -> Option<usize> {
        self.edges.get(n).map(|n| n.pointing_node as usize)
    }

    #[inline]
    fn nth_edge_weight(&self, n: usize) -> Option<EdgeWeight> {
        self.edges.get(n).map(|n| n.weight)
    }
}

#[derive(Debug)]
pub struct Node<T: Debug + Clone> {
    in_edges: EdgeList,
    out_edges: EdgeList,
    node_value: T,
}

impl<T: Debug + Clone> Node<T> {
    pub fn new(in_edges: EdgeList, out_edges: EdgeList, node_value: T) -> Node<T> {
        Node {
            in_edges: in_edges,
            out_edges: out_edges,
            node_value: node_value,
        }
    }

    pub fn node_value(&self) -> &T {
        &self.node_value
    }

    pub fn add_in_edge(&mut self, edge: Edge) {
        self.in_edges.edges.push(edge);
    }

    pub fn add_out_edge(&mut self, edge: Edge) {
        self.out_edges.edges.push(edge);
    }

    fn degree(&self) -> usize {
        self.in_edges.num_edges() + self.out_edges.num_edges()
    }
}

#[derive(Debug)]
pub struct OwnedGraph<T: Debug + Default + Clone> {
    nodes: Vec<Node<T>>,
}

impl<T: Debug + Default + Clone> OwnedGraph<T> {
    pub fn new(nodes: Vec<Node<T>>) -> OwnedGraph<T> {
        OwnedGraph { nodes: nodes }
    }

    pub fn from_petgraph(pg: &PetGraph<T, (), Directed>) -> OwnedGraph<T> {
        OwnedGraph {
            nodes: pg.node_indices()
                     .map(|i| {
                         Node::new(EdgeList::new(pg.edges_directed(i, EdgeDirection::Incoming)
                                                   .map(|(j, _w)| Edge::new_unweighted(j.index()))
                                                   .collect()),
                                   EdgeList::new(pg.edges_directed(i, EdgeDirection::Outgoing)
                                                   .map(|(j, _w)| Edge::new_unweighted(j.index()))
                                                   .collect()),
                                   pg.node_weight(i)
                                     .map(|v| v.clone())
                                     .unwrap_or_else(|| T::default()))
                     })
                     .collect(),
        }
    }

    pub fn len(&self) -> usize {
        self.nodes.len()
    }

    pub fn push_empty_node(&mut self, node_value: T) -> usize {
        let idx = self.nodes.len();
        self.nodes.push(Node::new(EdgeList::new(Vec::new()),
                                  EdgeList::new(Vec::new()),
                                  node_value));
        return idx;
    }
}

impl<T: Debug + Default + Clone> Graph for OwnedGraph<T> {
    type EDGE = EdgeList;
    type NODE = T;
    fn num_nodes(&self) -> usize {
        self.nodes.len()
    }

    #[inline]
    fn node_value(&self, node_idx: usize) -> &Self::NODE {
        self.nodes[node_idx].node_value()
    }

    #[inline]
    fn node_degree(&self, node_idx: usize) -> usize {
        self.nodes[node_idx].degree()
    }

    #[inline]
    fn in_edges_of<'b>(&'b self, node_idx: usize) -> &'b Self::EDGE {
        &&self.nodes[node_idx].in_edges
    }

    #[inline]
    fn out_edges_of<'b>(&'b self, node_idx: usize) -> &'b Self::EDGE {
        &self.nodes[node_idx].out_edges
    }
}

pub struct GraphBuilder<T: Debug + Default + Clone> {
    // maps node_id to index in node_in_edges/node_out_edges.
    node_map: BTreeMap<usize, usize>,
    graph: OwnedGraph<T>,
}

impl<T: Debug + Default + Clone> GraphBuilder<T> {
    pub fn new() -> GraphBuilder<T> {
        GraphBuilder {
            node_map: BTreeMap::new(),
            graph: OwnedGraph::new(Vec::new()),
        }
    }

    pub fn graph(self) -> OwnedGraph<T> {
        self.graph
    }

    /// Panics if `node_id` already exists.
    pub fn add_node(&mut self, node_id: usize, node_value: T) -> usize {
        match self.node_map.entry(node_id) {
            Entry::Vacant(e) => {
                let next_id = self.graph.push_empty_node(node_value);
                e.insert(next_id);
                return next_id;
            }
            Entry::Occupied(_) => {
                panic!();
            }
        }
    }

    pub fn add_edge_unweighted(&mut self, source_node_id: usize, target_node_id: usize) {
        self.add_edge(source_node_id, target_node_id, Closed01::zero());
    }

    pub fn add_edge(&mut self, source_node_id: usize, target_node_id: usize, weight: EdgeWeight) {
        let source_index = *self.node_map.get(&source_node_id).unwrap();
        let target_index = *self.node_map.get(&target_node_id).unwrap();
        self.graph.nodes[source_index].add_out_edge(Edge::new(target_index, weight));
        self.graph.nodes[target_index].add_in_edge(Edge::new(source_index, weight));
    }
}
<commit_msg>Get rid of Default. Instead pass default_node_weight to from_petgraph() directly.<commit_after>use super::traits::{EdgeWeight, Edges, Graph};
use closed01::Closed01;
use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use petgraph::{EdgeDirection, Directed};
use petgraph::Graph as PetGraph;
use std::fmt::Debug;

#[derive(Debug)]
pub struct Edge {
    /// Node index type. Our graphs never exceed 4 billion nodes.
    pointing_node: u32,
    weight: EdgeWeight,
}

impl Edge {
    pub fn new_unweighted(node_idx: usize) -> Edge {
        Edge::new(node_idx, Closed01::zero())
    }

    pub fn new(node_idx: usize, weight: EdgeWeight) -> Edge {
        assert!(node_idx <= u32::max_value() as usize);
        Edge {
            pointing_node: node_idx as u32,
            weight: weight,
        }
    }
}

#[derive(Debug)]
pub struct EdgeList {
    edges: Vec<Edge>,
}

impl EdgeList {
    pub fn new(edges: Vec<Edge>) -> EdgeList {
        EdgeList { edges: edges }
    }
}

impl Edges for EdgeList {
    #[inline]
    fn num_edges(&self) -> usize {
        self.edges.len()
    }

    #[inline]
    fn nth_edge(&self, n: usize) -> Option<usize> {
        self.edges.get(n).map(|n| n.pointing_node as usize)
    }

    #[inline]
    fn nth_edge_weight(&self, n: usize) -> Option<EdgeWeight> {
        self.edges.get(n).map(|n| n.weight)
    }
}

#[derive(Debug)]
pub struct Node<T: Debug + Clone> {
    in_edges: EdgeList,
    out_edges: EdgeList,
    node_value: T,
}

impl<T: Debug + Clone> Node<T> {
    pub fn new(in_edges: EdgeList, out_edges: EdgeList, node_value: T) -> Node<T> {
        Node {
            in_edges: in_edges,
            out_edges: out_edges,
            node_value: node_value,
        }
    }

    pub fn node_value(&self) -> &T {
        &self.node_value
    }

    pub fn add_in_edge(&mut self, edge: Edge) {
        self.in_edges.edges.push(edge);
    }

    pub fn add_out_edge(&mut self, edge: Edge) {
        self.out_edges.edges.push(edge);
    }

    fn degree(&self) -> usize {
        self.in_edges.num_edges() + self.out_edges.num_edges()
    }
}

#[derive(Debug)]
pub struct OwnedGraph<T: Debug + Clone> {
    nodes: Vec<Node<T>>,
}

impl<T: Debug + Clone> OwnedGraph<T> {
    pub fn new(nodes: Vec<Node<T>>) -> OwnedGraph<T> {
        OwnedGraph { nodes: nodes }
    }

    pub fn from_petgraph(pg: &PetGraph<T, (), Directed>, default_node_weight: T) -> OwnedGraph<T> {
        OwnedGraph {
            nodes: pg.node_indices()
                     .map(|i| {
                         Node::new(EdgeList::new(pg.edges_directed(i, EdgeDirection::Incoming)
                                                   .map(|(j, _w)| Edge::new_unweighted(j.index()))
                                                   .collect()),
                                   EdgeList::new(pg.edges_directed(i, EdgeDirection::Outgoing)
                                                   .map(|(j, _w)| Edge::new_unweighted(j.index()))
                                                   .collect()),
                                   pg.node_weight(i)
                                     .map(|v| v.clone())
                                     .unwrap_or_else(|| default_node_weight.clone()))
                     })
                     .collect(),
        }
    }

    pub fn len(&self) -> usize {
        self.nodes.len()
    }

    pub fn push_empty_node(&mut self, node_value: T) -> usize {
        let idx = self.nodes.len();
        self.nodes.push(Node::new(EdgeList::new(Vec::new()),
                                  EdgeList::new(Vec::new()),
                                  node_value));
        return idx;
    }
}

impl<T: Debug + Clone> Graph for OwnedGraph<T> {
    type EDGE = EdgeList;
    type NODE = T;
    fn num_nodes(&self) -> usize {
        self.nodes.len()
    }

    #[inline]
    fn node_value(&self, node_idx: usize) -> &Self::NODE {
        self.nodes[node_idx].node_value()
    }

    #[inline]
    fn node_degree(&self, node_idx: usize) -> usize {
        self.nodes[node_idx].degree()
    }

    #[inline]
    fn in_edges_of<'b>(&'b self, node_idx: usize) -> &'b Self::EDGE {
        &&self.nodes[node_idx].in_edges
    }

    #[inline]
    fn out_edges_of<'b>(&'b self, node_idx: usize) -> &'b Self::EDGE {
        &self.nodes[node_idx].out_edges
    }
}

pub struct GraphBuilder<T: Debug + Clone> {
    // maps node_id to index in node_in_edges/node_out_edges.
    node_map: BTreeMap<usize, usize>,
    graph: OwnedGraph<T>,
}

impl<T: Debug + Clone> GraphBuilder<T> {
    pub fn new() -> GraphBuilder<T> {
        GraphBuilder {
            node_map: BTreeMap::new(),
            graph: OwnedGraph::new(Vec::new()),
        }
    }

    pub fn graph(self) -> OwnedGraph<T> {
        self.graph
    }

    /// Panics if `node_id` already exists.
    pub fn add_node(&mut self, node_id: usize, node_value: T) -> usize {
        match self.node_map.entry(node_id) {
            Entry::Vacant(e) => {
                let next_id = self.graph.push_empty_node(node_value);
                e.insert(next_id);
                return next_id;
            }
            Entry::Occupied(_) => {
                panic!();
            }
        }
    }

    pub fn add_edge_unweighted(&mut self, source_node_id: usize, target_node_id: usize) {
        self.add_edge(source_node_id, target_node_id, Closed01::zero());
    }

    pub fn add_edge(&mut self, source_node_id: usize, target_node_id: usize, weight: EdgeWeight) {
        let source_index = *self.node_map.get(&source_node_id).unwrap();
        let target_index = *self.node_map.get(&target_node_id).unwrap();
        self.graph.nodes[source_index].add_out_edge(Edge::new(target_index, weight));
        self.graph.nodes[target_index].add_in_edge(Edge::new(source_index, weight));
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ops::Deref;
use std::slice::Iter;

use chrono::{DateTime, UTC};

use api::{CratesIO, ApiResponse, VersionData};
use errors::*;

#[derive(Debug)]
pub struct Version {
    pub num: String, // XXX should be semver::Version
    pub downloads: i32,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

impl Version {
    fn from_versiondata(data: &VersionData) -> Self {
        Version {
            num: data.num.clone(),
            downloads: data.downloads,
            created_at: data.created_at,
            updated_at: data.updated_at,
            features: data.features.clone(),
            yanked: data.yanked,
        }
    }
}

#[derive(Debug)]
pub struct Versions {
    versions: Vec<Version>,
}

impl Versions {
    fn by_id(id: i32, versions: &[VersionData]) -> Option<&VersionData> {
        for v in versions {
            if id == v.id {
                return Some(v);
            }
        }
        None
    }

    fn from_crate_data(data: &ApiResponse) -> Self {
        let mut versions = Vec::new();
        if let Some(vers) = data.krate.versions.as_ref() {
            for id in vers {
                if let Some(versiondata) = Versions::by_id(*id, &data.versions) {
                    versions.push(Version::from_versiondata(versiondata))
                }
            }
        }
        Versions { versions: versions }
    }

    pub fn iter(&self) -> Iter<Version> {
        self.versions.iter()
    }
}

impl Deref for Versions {
    type Target = [Version];
    fn deref(&self) -> &[Version] {
        &self.versions
    }
}

#[derive(Debug)]
pub struct Crate {
    pub id: String,
    pub name: String,
    pub updated_at: DateTime<UTC>,
    pub created_at: DateTime<UTC>,
    pub downloads: i32,
    pub max_version: String, // XXX Should be semver::Version
    pub description: Option<String>,
    pub homepage: Option<String>,
    pub documentation: Option<String>,
    pub readme: Option<String>,
    pub license: Option<String>,
    pub repository: Option<String>,
    pub max_upload_size: Option<i32>,
    pub versions: Versions,
    pub keywords: Vec<String>,
}

impl Crate {
    pub fn from_apiresponse(data: &ApiResponse) -> Result<Self> {
        let versions = Versions::from_crate_data(data);
        let keywords = data.krate.keywords.clone().unwrap_or(Vec::new());
        Ok(Crate {
               id: data.krate.id.clone(),
               name: data.krate.name.clone(),
               updated_at: data.krate.updated_at,
               created_at: data.krate.created_at,
               downloads: data.krate.downloads,
               max_version: data.krate.max_version.clone(),
               description: data.krate.description.clone(),
               homepage: data.krate.homepage.clone(),
               documentation: data.krate.documentation.clone(),
               readme: None,
               license: data.krate.license.clone(),
               repository: data.krate.repository.clone(),
               max_upload_size: None,
               versions: versions,
               keywords: keywords,
           })
    }

    pub fn by_name(name: &str) -> Result<Self> {
        let data = CratesIO::query(name)?.as_data()?;
        Crate::from_apiresponse(&data)
    }
}
<commit_msg>[clippy] unwrap_or() -> unwrap_or_default()<commit_after>use std::collections::HashMap;
use std::ops::Deref;
use std::slice::Iter;

use chrono::{DateTime, UTC};

use api::{CratesIO, ApiResponse, VersionData};
use errors::*;

#[derive(Debug)]
pub struct Version {
    pub num: String, // XXX should be semver::Version
    pub downloads: i32,
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub features: HashMap<String, Vec<String>>,
    pub yanked: bool,
}

impl Version {
    fn from_versiondata(data: &VersionData) -> Self {
        Version {
            num: data.num.clone(),
            downloads: data.downloads,
            created_at: data.created_at,
            updated_at: data.updated_at,
            features: data.features.clone(),
            yanked: data.yanked,
        }
    }
}

#[derive(Debug)]
pub struct Versions {
    versions: Vec<Version>,
}

impl Versions {
    fn by_id(id: i32, versions: &[VersionData]) -> Option<&VersionData> {
        for v in versions {
            if id == v.id {
                return Some(v);
            }
        }
        None
    }

    fn from_crate_data(data: &ApiResponse) -> Self {
        let mut versions = Vec::new();
        if let Some(vers) = data.krate.versions.as_ref() {
            for id in vers {
                if let Some(versiondata) = Versions::by_id(*id, &data.versions) {
                    versions.push(Version::from_versiondata(versiondata))
                }
            }
        }
        Versions { versions: versions }
    }

    pub fn iter(&self) -> Iter<Version> {
        self.versions.iter()
    }
}

impl Deref for Versions {
    type Target = [Version];
    fn deref(&self) -> &[Version] {
        &self.versions
    }
}

#[derive(Debug)]
pub struct Crate {
    pub id: String,
    pub name: String,
    pub updated_at: DateTime<UTC>,
    pub created_at: DateTime<UTC>,
    pub downloads: i32,
    pub max_version: String, // XXX Should be semver::Version
    pub description: Option<String>,
    pub homepage: Option<String>,
    pub documentation: Option<String>,
    pub readme: Option<String>,
    pub license: Option<String>,
    pub repository: Option<String>,
    pub max_upload_size: Option<i32>,
    pub versions: Versions,
    pub keywords: Vec<String>,
}

impl Crate {
    pub fn from_apiresponse(data: &ApiResponse) -> Result<Self> {
        let versions = Versions::from_crate_data(data);
        let keywords = data.krate.keywords.clone().unwrap_or_default();
        Ok(Crate {
               id: data.krate.id.clone(),
               name: data.krate.name.clone(),
               updated_at: data.krate.updated_at,
               created_at: data.krate.created_at,
               downloads: data.krate.downloads,
               max_version: data.krate.max_version.clone(),
               description: data.krate.description.clone(),
               homepage: data.krate.homepage.clone(),
               documentation: data.krate.documentation.clone(),
               readme: None,
               license: data.krate.license.clone(),
               repository: data.krate.repository.clone(),
               max_upload_size: None,
               versions: versions,
               keywords: keywords,
           })
    }

    pub fn by_name(name: &str) -> Result<Self> {
        let data = CratesIO::query(name)?.as_data()?;
        Crate::from_apiresponse(&data)
    }
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#![feature(test)]
extern crate test;
extern crate parquet;
use test::Bencher;

use std::rc::Rc;
use parquet::basic::*;
use parquet::data_type::*;
use parquet::encodings::encoding::*;
use parquet::schema::types::{Type as SchemaType, ColumnDescriptor, ColumnPath};
use parquet::util::memory::MemTracker;

const BATCH_SIZE: usize = 1024;

#[bench]
fn plain_encoding_bool(bench: &mut Bencher) {
  plain_encoding::<BoolType>(bench, vec![false; BATCH_SIZE], 1, Type::BOOLEAN);
}

#[bench]
fn plain_encoding_i32(bench: &mut Bencher) {
  plain_encoding::<Int32Type>(bench, vec![0; BATCH_SIZE], 4, Type::INT32);
}

#[bench]
fn plain_encoding_i64(bench: &mut Bencher) {
  plain_encoding::<Int64Type>(bench, vec![0; BATCH_SIZE], 8, Type::INT64);
}

fn plain_encoding<T: DataType>(bench: &mut Bencher, data: Vec<T::T>, type_length: i32, primitive_ty: Type) {
  let mem_tracker = MemTracker::new_ptr(None).expect("");
  let mut encoder = PlainEncoder::<T>::new(
    Rc::new(col_desc(type_length, primitive_ty)), mem_tracker, vec!());
  bench.iter(|| {
    let _ = encoder.put(&data[..]);
  })
}

fn col_desc(type_length: i32, primitive_ty: Type) -> ColumnDescriptor {
  let ty = SchemaType::new_primitive_type(
    "col", Repetition::OPTIONAL, primitive_ty, LogicalType::NONE, type_length, 0, 0, None).unwrap();
  ColumnDescriptor::new(Rc::new(ty), None, 0, 0, ColumnPath::new(vec!()))
}
<commit_msg>Fix benchmark<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#![feature(test)]
extern crate test;
extern crate parquet;
use test::Bencher;

use std::rc::Rc;
use parquet::basic::*;
use parquet::data_type::*;
use parquet::encodings::encoding::*;
use parquet::schema::types::{Type as SchemaType, ColumnDescriptor, ColumnPath};
use parquet::util::memory::MemTracker;

const BATCH_SIZE: usize = 1024;

#[bench]
fn plain_encoding_bool(bench: &mut Bencher) {
  plain_encoding::<BoolType>(bench, vec![false; BATCH_SIZE], 1, Type::BOOLEAN);
}

#[bench]
fn plain_encoding_i32(bench: &mut Bencher) {
  plain_encoding::<Int32Type>(bench, vec![0; BATCH_SIZE], 4, Type::INT32);
}

#[bench]
fn plain_encoding_i64(bench: &mut Bencher) {
  plain_encoding::<Int64Type>(bench, vec![0; BATCH_SIZE], 8, Type::INT64);
}

fn plain_encoding<T: DataType>(bench: &mut Bencher, data: Vec<T::T>, type_length: i32, primitive_ty: Type) {
  let mem_tracker = MemTracker::new_ptr(None).expect("");
  let mut encoder = PlainEncoder::<T>::new(
    Rc::new(col_desc(type_length, primitive_ty)), mem_tracker, vec!());
  bench.iter(|| {
    let _ = encoder.put(&data[..]);
  })
}

fn col_desc(type_length: i32, primitive_ty: Type) -> ColumnDescriptor {
  let ty = SchemaType::primitive_type_builder("col", primitive_ty)
    .with_length(type_length)
    .build()
    .unwrap();
  ColumnDescriptor::new(Rc::new(ty), None, 0, 0, ColumnPath::new(vec!()))
}
<|endoftext|>