<commit_before>#![feature(test)]

extern crate croaring;
extern crate roaring;
extern crate test;

use croaring::Bitmap;
use roaring::RoaringBitmap;
use test::{Bencher, black_box};

#[bench]
fn perf_comp_create_croaring(b: &mut Bencher) {
    b.iter(|| {
        let bitmap = Bitmap::create();

        black_box(bitmap);
    });
}

#[bench]
fn perf_comp_create_rust_roaring(b: &mut Bencher) {
    b.iter(|| {
        let bitmap: RoaringBitmap<u32> = RoaringBitmap::new();

        black_box(bitmap);
    });
}

#[bench]
fn perf_comp_create_and_add_one_croaring(b: &mut Bencher) {
    b.iter(|| {
        let mut bitmap = Bitmap::create();
        bitmap.add(black_box(1));

        black_box(bitmap);
    });
}

#[bench]
fn perf_comp_create_and_add_one_rust_roaring(b: &mut Bencher) {
    b.iter(|| {
        let mut bitmap: RoaringBitmap<u32> = RoaringBitmap::new();
        bitmap.insert(black_box(1));

        black_box(bitmap);
    });
}

#[bench]
fn perf_comp_add_croaring(b: &mut Bencher) {
    let mut bitmap = Bitmap::create();

    b.iter(|| {
        bitmap.add(black_box(1));
        bitmap.add(black_box(10));
        bitmap.add(black_box(100));
        bitmap.add(black_box(1000));
        bitmap.add(black_box(10000));
        bitmap.add(black_box(100000));
        bitmap.add(black_box(1000000));
    });
    black_box(bitmap);
}

#[bench]
fn perf_comp_add_many_croaring(b: &mut Bencher) {
    let mut bitmap = Bitmap::create();

    b.iter(|| {
        let int_slice = &[1, 10, 100, 1000, 10_000, 100_000, 1_000_000];
        bitmap.add_many(int_slice);
    });
    black_box(bitmap);
}

#[bench]
fn perf_comp_add_rust_roaring(b: &mut Bencher) {
    let mut bitmap: RoaringBitmap<u32> = RoaringBitmap::new();

    b.iter(|| {
        bitmap.insert(black_box(1));
        bitmap.insert(black_box(10));
        bitmap.insert(black_box(100));
        bitmap.insert(black_box(1000));
        bitmap.insert(black_box(10000));
        bitmap.insert(black_box(100000));
        bitmap.insert(black_box(1000000));
    });
    black_box(bitmap);
}

#[bench]
fn perf_comp_remove_croaring(b: &mut Bencher) {
    let mut bitmap = Bitmap::create();
    bitmap.add(1);
    bitmap.add(10);
    bitmap.add(100);
    bitmap.add(1000);
    bitmap.add(10000);
    bitmap.add(100000);
    bitmap.add(1000000);

    b.iter(|| {
        bitmap.remove(black_box(1000000));
    });
}

#[bench]
fn perf_comp_remove_rust_roaring(b: &mut Bencher) {
    let mut bitmap: RoaringBitmap<u32> = RoaringBitmap::new();
    bitmap.insert(1);
    bitmap.insert(10);
    bitmap.insert(100);
    bitmap.insert(1000);
    bitmap.insert(10000);
    bitmap.insert(100000);
    bitmap.insert(1000000);

    b.iter(|| {
        bitmap.remove(black_box(1000000));
    });
}

#[bench]
fn perf_comp_contains_true_croaring(b: &mut Bencher) {
    let mut bitmap = Bitmap::create();
    bitmap.add(1);

    b.iter(|| {
        bitmap.contains(black_box(1));
    });
}

#[bench]
fn perf_comp_contains_true_rust_roaring(b: &mut Bencher) {
    let mut bitmap: RoaringBitmap<u32> = RoaringBitmap::new();
    bitmap.insert(1);

    b.iter(|| {
        bitmap.contains(black_box(1));
    });
}

#[bench]
fn perf_comp_contains_false_croaring(b: &mut Bencher) {
    let bitmap = Bitmap::create();

    b.iter(|| {
        bitmap.contains(black_box(1));
    });
}

#[bench]
fn perf_comp_contains_false_rust_roaring(b: &mut Bencher) {
    let bitmap: RoaringBitmap<u32> = RoaringBitmap::new();

    b.iter(|| {
        bitmap.contains(black_box(1));
    });
}

#[bench]
fn perf_comp_cardinality_100000_croaring(b: &mut Bencher) {
    let bitmap: Bitmap = (1..100000).collect();

    b.iter(|| {
        black_box(bitmap.cardinality());
    });
}

#[bench]
fn perf_comp_cardinality_100000_rust_roaring(b: &mut Bencher) {
    let bitmap: RoaringBitmap<u32> = (1..100000).collect();

    b.iter(|| {
        black_box(bitmap.len());
    });
}

#[bench]
fn perf_comp_and_new_croaring(b: &mut Bencher) {
    let bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.and(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_and_new_rust_roaring(b: &mut Bencher) {
    let bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        let bitmap3: RoaringBitmap<u32> = bitmap1.intersection(black_box(&bitmap2)).collect();

        bitmap3
    });
}

#[bench]
fn perf_comp_and_inplace_croaring(b: &mut Bencher) {
    let mut bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.and_inplace(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_and_inplace_rust_roaring(b: &mut Bencher) {
    let mut bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        bitmap1.intersect_with(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_or_new_croaring(b: &mut Bencher) {
    let bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.or(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_or_new_rust_roaring(b: &mut Bencher) {
    let bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        let bitmap3: RoaringBitmap<u32> = bitmap1.union(black_box(&bitmap2)).collect();

        bitmap3
    });
}

#[bench]
fn perf_comp_or_inplace_croaring(b: &mut Bencher) {
    let mut bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.or_inplace(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_or_inplace_rust_roaring(b: &mut Bencher) {
    let mut bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        bitmap1.union_with(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_xor_new_croaring(b: &mut Bencher) {
    let bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.xor(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_xor_new_rust_roaring(b: &mut Bencher) {
    let bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        let bitmap3: RoaringBitmap<u32> = bitmap1.symmetric_difference(black_box(&bitmap2)).collect();

        bitmap3
    });
}

#[bench]
fn perf_comp_xor_inplace_croaring(b: &mut Bencher) {
    let mut bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.xor_inplace(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_xor_inplace_rust_roaring(b: &mut Bencher) {
    let mut bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        bitmap1.symmetric_difference_with(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_iter_croaring(b: &mut Bencher) {
    let bitmap: Bitmap = (1..10000).collect();

    b.iter(|| {
        let mut sum: u32 = 0;

        for (_, element) in bitmap.into_iter().enumerate() {
            sum += *element;
        }

        assert_eq!(sum, 49995000);
    });
}

#[bench]
fn perf_comp_iter_rust_roaring(b: &mut Bencher) {
    let bitmap: RoaringBitmap<u32> = (1..10000).collect();

    b.iter(|| {
        let mut sum: u32 = 0;

        for (_, element) in bitmap.iter().enumerate() {
            sum += element;
        }

        assert_eq!(sum, 49995000);
    });
}
<commit_msg>Fix roaring-rs benchmarks to use specialized operators<commit_after>#![feature(test)]

extern crate croaring;
extern crate roaring;
extern crate test;

use croaring::Bitmap;
use roaring::RoaringBitmap;
use test::{Bencher, black_box};

#[bench]
fn perf_comp_create_croaring(b: &mut Bencher) {
    b.iter(|| {
        let bitmap = Bitmap::create();

        black_box(bitmap);
    });
}

#[bench]
fn perf_comp_create_rust_roaring(b: &mut Bencher) {
    b.iter(|| {
        let bitmap: RoaringBitmap<u32> = RoaringBitmap::new();

        black_box(bitmap);
    });
}

#[bench]
fn perf_comp_create_and_add_one_croaring(b: &mut Bencher) {
    b.iter(|| {
        let mut bitmap = Bitmap::create();
        bitmap.add(black_box(1));

        black_box(bitmap);
    });
}

#[bench]
fn perf_comp_create_and_add_one_rust_roaring(b: &mut Bencher) {
    b.iter(|| {
        let mut bitmap: RoaringBitmap<u32> = RoaringBitmap::new();
        bitmap.insert(black_box(1));

        black_box(bitmap);
    });
}

#[bench]
fn perf_comp_add_croaring(b: &mut Bencher) {
    let mut bitmap = Bitmap::create();

    b.iter(|| {
        bitmap.add(black_box(1));
        bitmap.add(black_box(10));
        bitmap.add(black_box(100));
        bitmap.add(black_box(1000));
        bitmap.add(black_box(10000));
        bitmap.add(black_box(100000));
        bitmap.add(black_box(1000000));
    });
    black_box(bitmap);
}

#[bench]
fn perf_comp_add_many_croaring(b: &mut Bencher) {
    let mut bitmap = Bitmap::create();

    b.iter(|| {
        let int_slice = &[1, 10, 100, 1000, 10_000, 100_000, 1_000_000];
        bitmap.add_many(int_slice);
    });
    black_box(bitmap);
}

#[bench]
fn perf_comp_add_rust_roaring(b: &mut Bencher) {
    let mut bitmap: RoaringBitmap<u32> = RoaringBitmap::new();

    b.iter(|| {
        bitmap.insert(black_box(1));
        bitmap.insert(black_box(10));
        bitmap.insert(black_box(100));
        bitmap.insert(black_box(1000));
        bitmap.insert(black_box(10000));
        bitmap.insert(black_box(100000));
        bitmap.insert(black_box(1000000));
    });
    black_box(bitmap);
}

#[bench]
fn perf_comp_remove_croaring(b: &mut Bencher) {
    let mut bitmap = Bitmap::create();
    bitmap.add(1);
    bitmap.add(10);
    bitmap.add(100);
    bitmap.add(1000);
    bitmap.add(10000);
    bitmap.add(100000);
    bitmap.add(1000000);

    b.iter(|| {
        bitmap.remove(black_box(1000000));
    });
}

#[bench]
fn perf_comp_remove_rust_roaring(b: &mut Bencher) {
    let mut bitmap: RoaringBitmap<u32> = RoaringBitmap::new();
    bitmap.insert(1);
    bitmap.insert(10);
    bitmap.insert(100);
    bitmap.insert(1000);
    bitmap.insert(10000);
    bitmap.insert(100000);
    bitmap.insert(1000000);

    b.iter(|| {
        bitmap.remove(black_box(1000000));
    });
}

#[bench]
fn perf_comp_contains_true_croaring(b: &mut Bencher) {
    let mut bitmap = Bitmap::create();
    bitmap.add(1);

    b.iter(|| {
        bitmap.contains(black_box(1));
    });
}

#[bench]
fn perf_comp_contains_true_rust_roaring(b: &mut Bencher) {
    let mut bitmap: RoaringBitmap<u32> = RoaringBitmap::new();
    bitmap.insert(1);

    b.iter(|| {
        bitmap.contains(black_box(1));
    });
}

#[bench]
fn perf_comp_contains_false_croaring(b: &mut Bencher) {
    let bitmap = Bitmap::create();

    b.iter(|| {
        bitmap.contains(black_box(1));
    });
}

#[bench]
fn perf_comp_contains_false_rust_roaring(b: &mut Bencher) {
    let bitmap: RoaringBitmap<u32> = RoaringBitmap::new();

    b.iter(|| {
        bitmap.contains(black_box(1));
    });
}

#[bench]
fn perf_comp_cardinality_100000_croaring(b: &mut Bencher) {
    let bitmap: Bitmap = (1..100000).collect();

    b.iter(|| {
        black_box(bitmap.cardinality());
    });
}

#[bench]
fn perf_comp_cardinality_100000_rust_roaring(b: &mut Bencher) {
    let bitmap: RoaringBitmap<u32> = (1..100000).collect();

    b.iter(|| {
        black_box(bitmap.len());
    });
}

#[bench]
fn perf_comp_and_new_croaring(b: &mut Bencher) {
    let bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.and(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_and_new_rust_roaring(b: &mut Bencher) {
    let bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        &bitmap1 & &bitmap2
    });
}

#[bench]
fn perf_comp_and_inplace_croaring(b: &mut Bencher) {
    let mut bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.and_inplace(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_and_inplace_rust_roaring(b: &mut Bencher) {
    let mut bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        bitmap1.intersect_with(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_or_new_croaring(b: &mut Bencher) {
    let bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.or(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_or_new_rust_roaring(b: &mut Bencher) {
    let bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        &bitmap1 | &bitmap2
    });
}

#[bench]
fn perf_comp_or_inplace_croaring(b: &mut Bencher) {
    let mut bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.or_inplace(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_or_inplace_rust_roaring(b: &mut Bencher) {
    let mut bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        bitmap1.union_with(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_xor_new_croaring(b: &mut Bencher) {
    let bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.xor(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_xor_new_rust_roaring(b: &mut Bencher) {
    let bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        &bitmap1 ^ &bitmap2
    });
}

#[bench]
fn perf_comp_xor_inplace_croaring(b: &mut Bencher) {
    let mut bitmap1: Bitmap = (1..100).collect();
    let bitmap2: Bitmap = (100..200).collect();

    b.iter(|| {
        bitmap1.xor_inplace(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_xor_inplace_rust_roaring(b: &mut Bencher) {
    let mut bitmap1: RoaringBitmap<u32> = (1..100).collect();
    let bitmap2: RoaringBitmap<u32> = (100..200).collect();

    b.iter(|| {
        bitmap1.symmetric_difference_with(black_box(&bitmap2));
    });
}

#[bench]
fn perf_comp_iter_croaring(b: &mut Bencher) {
    let bitmap: Bitmap = (1..10000).collect();

    b.iter(|| {
        let mut sum: u32 = 0;

        for (_, element) in bitmap.into_iter().enumerate() {
            sum += *element;
        }

        assert_eq!(sum, 49995000);
    });
}

#[bench]
fn perf_comp_iter_rust_roaring(b: &mut Bencher) {
    let bitmap: RoaringBitmap<u32> = (1..10000).collect();

    b.iter(|| {
        let mut sum: u32 = 0;

        for (_, element) in bitmap.iter().enumerate() {
            sum += element;
        }

        assert_eq!(sum, 49995000);
    });
}
<|endoftext|>


<commit_before>use gfx;
use gfx_phase;
use gfx_phase::Object;
use gfx_scene;
use std::cmp::Ordering;

pub fn order<S: PartialOrd, R: gfx::Resources>(
             a: &Object<S, super::Kernel, super::Params<R>>,
             b: &Object<S, super::Kernel, super::Params<R>>)
             -> Ordering {
    match (a.kernel, b.kernel) {
        (None, None)        => Object::front_to_back(a, b),
        (None, Some(_))     => Ordering::Less,
        (Some(_), None)     => Ordering::Greater,
        (Some(_), Some(_))  => Object::back_to_front(a, b),
    }
}

pub struct Pipeline<D: gfx::Device> {
    pub phase: super::Phase<D::Resources>,
    pub renderer: gfx::Renderer<D::Resources, D::CommandBuffer>,
}

impl<D: gfx::Device> ::Pipeline<f32, D> for Pipeline<D> {
    fn render<
        C: gfx_scene::OrderedScene<D::Resources, ViewInfo = ::view::Info<f32>>,
    >(  &mut self, scene: &C, camera: &C::Camera,
        frame: &gfx::Frame<D::Resources>)
        -> Result<gfx::SubmitInfo<D>, gfx_scene::Error>
    where
        C::Entity: gfx_phase::Entity<D::Resources, ::Material<D::Resources>>,
    {
        match scene.draw_ordered(&mut self.phase, order, camera, frame, &mut self.renderer)  {
            Ok(_) => Ok(self.renderer.as_buffer()),
            Err(e) => Err(e),
        }
    }
}
<commit_msg>Added Forward pipeline constructor<commit_after>use gfx;
use gfx_phase;
use gfx_phase::Object;
use gfx_scene;
use std::cmp::Ordering;

pub fn order<S: PartialOrd, R: gfx::Resources>(
             a: &Object<S, super::Kernel, super::Params<R>>,
             b: &Object<S, super::Kernel, super::Params<R>>)
             -> Ordering {
    match (a.kernel, b.kernel) {
        (None, None)        => Object::front_to_back(a, b),
        (None, Some(_))     => Ordering::Less,
        (Some(_), None)     => Ordering::Greater,
        (Some(_), Some(_))  => Object::back_to_front(a, b),
    }
}

pub struct Pipeline<D: gfx::Device> {
    pub phase: super::Phase<D::Resources>,
    pub renderer: gfx::Renderer<D::Resources, D::CommandBuffer>,
}

impl<
    R: gfx::Resources,
    C: gfx::CommandBuffer<R>,
    D: gfx::Device<Resources = R, CommandBuffer = C> + gfx::Factory<R>
> Pipeline<D>{
    pub fn new(device: &mut D, tex_default: gfx::shade::TextureParam<R>)
               -> Result<Pipeline<D>, gfx::ProgramError> {
        use gfx::traits::DeviceExt;
        let renderer = device.create_renderer();
        super::Technique::new(device, tex_default).map(|tech| Pipeline {
            phase: gfx_phase::Phase::new_cached("Main", tech),
            renderer: renderer,
        })
    }
}

impl<D: gfx::Device> ::Pipeline<f32, D> for Pipeline<D> {
    fn render<
        C: gfx_scene::OrderedScene<D::Resources, ViewInfo = ::view::Info<f32>>,
    >(  &mut self, scene: &C, camera: &C::Camera,
        frame: &gfx::Frame<D::Resources>)
        -> Result<gfx::SubmitInfo<D>, gfx_scene::Error>
    where
        C::Entity: gfx_phase::Entity<D::Resources, ::Material<D::Resources>>,
    {
        match scene.draw_ordered(&mut self.phase, order, camera, frame, &mut self.renderer)  {
            Ok(_) => Ok(self.renderer.as_buffer()),
            Err(e) => Err(e),
        }
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS init parameters
//!
//! This crate is intended to facilitate the sharing of initialization
//! parameters between "higher-level" SOS subcrates (such as [`alloc`] and
//! [`paging`]) in a platform-independent way.
//!
//! [`alloc`](../alloc)
//! [`paging`](../paging)
#![no_std]
#![deny(missing_docs)]

extern crate memory;
extern crate elf;
// use memory::paging::PageRange;
use memory::PAddr;

/// If we are on x86_64 or armv7 this uses the 64-bit ELF word
#[cfg(target_pointer_width = "64")]
pub type ElfSections<'a> = elf::section::Sections<'a, u64>;

/// If we are on x86, this uses the 32-bit ELF word
#[cfg(target_pointer_width = "32")]
pub type ElfSections<'a> = elf::section::Sections<'a, u32>;

/// Parameters used during the init process
pub struct InitParams {
    /// The base of the kernel memory range
    // TODO: rewrite to use FrameRange once that's on master
    pub kernel_base: PAddr
  , /// The top of the kernel memory range
    // TODO: rewrite to use FrameRange once that's on master
    pub kernel_top: PAddr
  , /// The base of the memory range for the kernel heap
    // TODO: rewrite to use FrameRange once that's on master
    pub heap_base: PAddr
  , /// The top of the memory range to use for the kernel heap
    // TODO: rewrite to use FrameRange once that's on master
    pub heap_top: PAddr
}

impl InitParams {
    /// Returns an iterator over the kernel's ELF sections
    // TODO: is this cross-platform? are we using ELF on all our supported
    //       architectures? i think we are, but we should ensure this is the
    //       case...
    //          – eliza, 1/22/2017
    pub fn elf_sections(&self) ->  ElfSections {
        unimplemented!()
    }

    /// Returns the start address of the multiboot info struct
    pub fn multiboot_start(&self) -> PAddr {
        unimplemented!()
    }

    /// Returns the end address of the multiboot info struct
    pub fn multiboot_end(&self) -> PAddr {
        unimplemented!()
    }
}
<commit_msg>[params] add functions to init params<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS init parameters
//!
//! This crate is intended to facilitate the sharing of initialization
//! parameters between "higher-level" SOS subcrates (such as [`alloc`] and
//! [`paging`]) in a platform-independent way.
//!
//! [`alloc`](../alloc)
//! [`paging`](../paging)
#![no_std]
#![deny(missing_docs)]

extern crate memory;
extern crate elf;

use memory::{ PAddr, Page, PhysicalPage, FrameRange };

/// If we are on x86_64 or armv7 this uses the 64-bit ELF word
#[cfg(target_pointer_width = "64")]
pub type ElfSections<'a> = elf::section::Sections<'a, u64>;

/// If we are on x86, this uses the 32-bit ELF word
#[cfg(target_pointer_width = "32")]
pub type ElfSections<'a> = elf::section::Sections<'a, u32>;

/// Parameters used during the init process
pub struct InitParams {
    /// The base of the kernel memory range
    pub kernel_base: PAddr
  , /// The top of the kernel memory range
    pub kernel_top: PAddr
  , /// The base of the memory range for the kernel heap
    pub heap_base: PAddr
  , /// The top of the memory range to use for the kernel heap
    pub heap_top: PAddr
}

impl InitParams {
    /// Returns an iterator over the kernel's ELF sections
    // TODO: is this cross-platform? are we using ELF on all our supported
    //       architectures? i think we are, but we should ensure this is the
    //       case...
    //          – eliza, 1/22/2017
    pub fn elf_sections(&self) ->  ElfSections {
        unimplemented!()
    }

    /// Returns the start address of the multiboot info struct
    pub fn multiboot_start(&self) -> PAddr {
        unimplemented!()
    }

    /// Returns the end address of the multiboot info struct
    pub fn multiboot_end(&self) -> PAddr {
        unimplemented!()
    }

    /// Returns the range of frames containing the kernel binary.
    ///
    /// The kernel _should_ start on the first address in the frame range,
    /// since the kernel should be page aligned.
    #[inline]
    pub fn kernel_frames(&self) -> FrameRange {
        // TODO: assert that the kernel base addr is page aligned here?
        //       this should maybe be a debug assertion?
        //          - eliza, 1/22/2017
        PhysicalPage::containing(self.kernel_base) ..
        PhysicalPage::containing(self.kernel_top)
    }

    /// Returns the range of frames containing the kernel heap
    ///
    /// The heap _should_ start on the first address in the frame range,
    /// since the heap should be page aligned.
    #[inline]
    pub fn heap_frames(&self) -> FrameRange {
        // TODO: assert that the heap base addr is page aligned here?
        //       this should maybe be a debug assertion?
        //          - eliza, 1/22/2017
        PhysicalPage::containing(self.heap_base) ..
        PhysicalPage::containing(self.heap_top)
    }

    /// Returns the range of frames containing the kernel stack.
    #[inline]
    pub fn stack_frames(&self) -> FrameRange {
        unimplemented!()
    }

}
<|endoftext|>


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

/*! The Rust Runtime, including the task scheduler and I/O

The `rt` module provides the private runtime infrastructure necessary
to support core language features like the exchange and local heap,
the garbage collector, logging, local data and unwinding. It also
implements the default task scheduler and task model. Initialization
routines are provided for setting up runtime resources in common
configurations, including that used by `rustc` when generating
executables.

It is intended that the features provided by `rt` can be factored in a
way such that the core library can be built with different 'profiles'
for different use cases, e.g. excluding the task scheduler. A number
of runtime features though are critical to the functioning of the
language and an implementation must be provided regardless of the
execution environment.

Of foremost importance is the global exchange heap, in the module
`global_heap`. Very little practical Rust code can be written without
access to the global heap. Unlike most of `rt` the global heap is
truly a global resource and generally operates independently of the
rest of the runtime.

All other runtime features are task-local, including the local heap,
the garbage collector, local storage, logging and the stack unwinder.

The relationship between `rt` and the rest of the core library is
not entirely clear yet and some modules will be moving into or
out of `rt` as development proceeds.

Several modules in `core` are clients of `rt`:

* `std::task` - The user-facing interface to the Rust task model.
* `std::task::local_data` - The interface to local data.
* `std::gc` - The garbage collector.
* `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`.
* `std::condition` - Uses local data.
* `std::cleanup` - Local heap destruction.
* `std::io` - In the future `std::io` will use an `rt` implementation.
* `std::logging`
* `std::pipes`
* `std::comm`
* `std::stackwalk`

*/

// XXX: this should not be here.
#[allow(missing_doc)];

use clone::Clone;
use container::Container;
use iter::Iterator;
use option::{Option, None, Some};
use ptr::RawPtr;
use rt::local::Local;
use rt::sched::{Scheduler, Shutdown};
use rt::sleeper_list::SleeperList;
use task::TaskResult;
use rt::task::{Task, SchedTask, GreenTask, Sched};
use send_str::SendStrStatic;
use unstable::atomics::{AtomicInt, AtomicBool, SeqCst};
use unstable::sync::UnsafeArc;
use vec::{OwnedVector, MutableVector, ImmutableVector};
use vec;

use self::thread::Thread;

// the os module needs to reach into this helper, so allow general access
// through this reexport.
pub use self::util::set_exit_status;

// this is somewhat useful when a program wants to spawn a "reasonable" number
// of workers based on the constraints of the system that it's running on.
// Perhaps this shouldn't be a `pub use` though and there should be another
// method...
pub use self::util::default_sched_threads;

// Re-export of the functionality in the kill module
pub use self::kill::BlockedTask;

// XXX: these probably shouldn't be public...
#[doc(hidden)]
pub mod shouldnt_be_public {
    pub use super::local_ptr::native::maybe_tls_key;
    #[cfg(not(windows), not(target_os = "android"))]
    pub use super::local_ptr::compiled::RT_TLS_PTR;
}

// Internal macros used by the runtime.
mod macros;

/// Basic implementation of an EventLoop, provides no I/O interfaces
mod basic;

/// The global (exchange) heap.
pub mod global_heap;

/// Implementations of language-critical runtime features like @.
pub mod task;

/// Facilities related to task failure, killing, and death.
mod kill;

/// The coroutine task scheduler, built on the `io` event loop.
pub mod sched;

/// The EventLoop and internal synchronous I/O interface.
pub mod rtio;

/// The Local trait for types that are accessible via thread-local
/// or task-local storage.
pub mod local;

/// A mostly lock-free multi-producer, single consumer queue.
pub mod mpsc_queue;

/// A lock-free single-producer, single consumer queue.
pub mod spsc_queue;

/// A lock-free multi-producer, multi-consumer bounded queue.
mod mpmc_bounded_queue;

/// A parallel work-stealing deque
pub mod deque;

/// A parallel data structure for tracking sleeping schedulers.
pub mod sleeper_list;

/// Stack segments and caching.
pub mod stack;

/// CPU context swapping.
mod context;

/// Bindings to system threading libraries.
pub mod thread;

/// The runtime configuration, read from environment variables.
pub mod env;

/// The local, managed heap
pub mod local_heap;

/// The Logger trait and implementations
pub mod logging;

/// Crate map
pub mod crate_map;

/// Tools for testing the runtime
pub mod test;

/// Reference counting
pub mod rc;

/// A simple single-threaded channel type for passing buffered data between
/// scheduler and task context
pub mod tube;

/// The runtime needs to be able to put a pointer into thread-local storage.
mod local_ptr;

/// Bindings to pthread/windows thread-local storage.
mod thread_local_storage;

/// Stack unwinding
pub mod unwind;

/// Just stuff
mod util;

// Global command line argument storage
pub mod args;

// Support for dynamic borrowck
pub mod borrowck;

/// Set up a default runtime configuration, given compiler-supplied arguments.
///
/// This is invoked by the `start` _language item_ (unstable::lang) to
/// run a Rust executable.
///
/// # Arguments
///
/// * `argc` & `argv` - The argument vector. On Unix this information is used
///   by os::args.
///
/// # Return value
///
/// The return value is used as the process return code. 0 on success, 101 on error.
pub fn start(argc: int, argv: **u8, main: proc()) -> int {

    init(argc, argv);
    let exit_code = run(main);
    // unsafe is ok b/c we're sure that the runtime is gone
    unsafe { cleanup(); }

    return exit_code;
}

/// Like `start` but creates an additional scheduler on the current thread,
/// which in most cases will be the 'main' thread, and pins the main task to it.
///
/// This is appropriate for running code that must execute on the main thread,
/// such as the platform event loop and GUI.
pub fn start_on_main_thread(argc: int, argv: **u8, main: proc()) -> int {
    init(argc, argv);
    let exit_code = run_on_main_thread(main);
    // unsafe is ok b/c we're sure that the runtime is gone
    unsafe { cleanup(); }

    return exit_code;
}

/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
/// the crate's logging flags, registering GC
/// metadata, and storing the process arguments.
pub fn init(argc: int, argv: **u8) {
    // XXX: Derefing these pointers is not safe.
    // Need to propagate the unsafety to `start`.
    unsafe {
        args::init(argc, argv);
        env::init();
        logging::init();
    }
}

/// One-time runtime cleanup.
///
/// This function is unsafe because it performs no checks to ensure that the
/// runtime has completely ceased running. It is the responsibility of the
/// caller to ensure that the runtime is entirely shut down and nothing will be
/// poking around at the internal components.
///
/// Invoking cleanup while portions of the runtime are still in use may cause
/// undefined behavior.
pub unsafe fn cleanup() {
    args::cleanup();
    local_ptr::cleanup();
}

/// Execute the main function in a scheduler.
///
/// Configures the runtime according to the environment, by default
/// using a task scheduler with the same number of threads as cores.
/// Returns a process exit code.
pub fn run(main: proc()) -> int {
    run_(main, false)
}

pub fn run_on_main_thread(main: proc()) -> int {
    run_(main, true)
}

fn run_(main: proc(), use_main_sched: bool) -> int {
    static DEFAULT_ERROR_CODE: int = 101;

    let nscheds = util::default_sched_threads();

    let mut main = Some(main);

    // The shared list of sleeping schedulers.
    let sleepers = SleeperList::new();

    // Create a work queue for each scheduler, ntimes. Create an extra
    // for the main thread if that flag is set. We won't steal from it.
    let mut pool = deque::BufferPool::new();
    let arr = vec::from_fn(nscheds, |_| pool.deque());
    let (workers, stealers) = vec::unzip(arr.move_iter());

    // The schedulers.
    let mut scheds = ~[];
    // Handles to the schedulers. When the main task ends these will be
    // sent the Shutdown message to terminate the schedulers.
    let mut handles = ~[];

    for worker in workers.move_iter() {
        rtdebug!("inserting a regular scheduler");

        // Every scheduler is driven by an I/O event loop.
        let loop_ = new_event_loop();
        let mut sched = ~Scheduler::new(loop_,
                                        worker,
                                        stealers.clone(),
                                        sleepers.clone());
        let handle = sched.make_handle();

        scheds.push(sched);
        handles.push(handle);
    }

    // If we need a main-thread task then create a main thread scheduler
    // that will reject any task that isn't pinned to it
    let main_sched = if use_main_sched {

        // Create a friend handle.
        let mut friend_sched = scheds.pop();
        let friend_handle = friend_sched.make_handle();
        scheds.push(friend_sched);

        // This scheduler needs a queue that isn't part of the stealee
        // set.
        let (worker, _) = pool.deque();

        let main_loop = new_event_loop();
        let mut main_sched = ~Scheduler::new_special(main_loop,
                                                     worker,
                                                     stealers.clone(),
                                                     sleepers.clone(),
                                                     false,
                                                     Some(friend_handle));
        let mut main_handle = main_sched.make_handle();
        // Allow the scheduler to exit when the main task exits.
        // Note: sending the shutdown message also prevents the scheduler
        // from pushing itself to the sleeper list, which is used for
        // waking up schedulers for work stealing; since this is a
        // non-work-stealing scheduler it should not be adding itself
        // to the list.
        main_handle.send(Shutdown);
        Some(main_sched)
    } else {
        None
    };

    // Create a shared cell for transmitting the process exit
    // code from the main task to this function.
    let exit_code = UnsafeArc::new(AtomicInt::new(0));
    let exit_code_clone = exit_code.clone();

    // Used to sanity check that the runtime only exits once
    let exited_already = UnsafeArc::new(AtomicBool::new(false));

    // When the main task exits, after all the tasks in the main
    // task tree, shut down the schedulers and set the exit code.
    let handles = handles;
    let on_exit: proc(TaskResult) = proc(exit_success) {
        unsafe {
            assert!(!(*exited_already.get()).swap(true, SeqCst),
                    "the runtime already exited");
        }

        let mut handles = handles;
        for handle in handles.mut_iter() {
            handle.send(Shutdown);
        }

        unsafe {
            let exit_code = if exit_success.is_ok() {
                use rt::util;

                // If we're exiting successfully, then return the global
                // exit status, which can be set programmatically.
                util::get_exit_status()
            } else {
                DEFAULT_ERROR_CODE
            };
            (*exit_code_clone.get()).store(exit_code, SeqCst);
        }
    };

    let mut threads = ~[];
    let mut on_exit = Some(on_exit);

    if !use_main_sched {

        // In the case where we do not use a main_thread scheduler we
        // run the main task in one of our threads.

        let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
                                            None,
                                            ::util::replace(&mut main,
                                                            None).unwrap());
        main_task.name = Some(SendStrStatic("<main>"));
        main_task.death.on_exit = ::util::replace(&mut on_exit, None);

        let sched = scheds.pop();
        let main_task = main_task;
        let thread = do Thread::start {
            sched.bootstrap(main_task);
        };
        threads.push(thread);
    }

    // Run each remaining scheduler in a thread.
    for sched in scheds.move_rev_iter() {
        rtdebug!("creating regular schedulers");
        let thread = do Thread::start {
            let mut sched = sched;
            let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
                rtdebug!("boostraping a non-primary scheduler");
            };
            sched.bootstrap(bootstrap_task);
        };
        threads.push(thread);
    }

    // If we do have a main thread scheduler, run it now.

    if use_main_sched {
        rtdebug!("about to create the main scheduler task");

        let mut main_sched = main_sched.unwrap();

        let home = Sched(main_sched.make_handle());
        let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
                                                  None,
                                                  home,
                                                  ::util::replace(&mut main,
                                                                  None).
                                                                  unwrap());
        main_task.name = Some(SendStrStatic("<main>"));
        main_task.death.on_exit = ::util::replace(&mut on_exit, None);
        rtdebug!("bootstrapping main_task");

        main_sched.bootstrap(main_task);
    }

    rtdebug!("waiting for threads");

    // Wait for schedulers
    for thread in threads.move_iter() {
        thread.join();
    }

    // Return the exit code
    unsafe {
        (*exit_code.get()).load(SeqCst)
    }
}

pub fn in_sched_context() -> bool {
    unsafe {
        let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
        match task_ptr {
            Some(task) => {
                match (*task).task_type {
                    SchedTask => true,
                    _ => false
                }
            }
            None => false
        }
    }
}

pub fn in_green_task_context() -> bool {
    unsafe {
        let task: Option<*mut Task> = Local::try_unsafe_borrow();
        match task {
            Some(task) => {
                match (*task).task_type {
                    GreenTask(_) => true,
                    _ => false
                }
            }
            None => false
        }
    }
}

pub fn new_event_loop() -> ~rtio::EventLoop {
    match crate_map::get_crate_map() {
        None => {}
        Some(map) => {
            match map.event_loop_factory {
                None => {}
                Some(factory) => return factory()
            }
        }
    }

    // If the crate map didn't specify a factory to create an event loop, then
    // instead just use a basic event loop missing all I/O services to at least
    // get the scheduler running.
    return basic::event_loop();
}
<commit_msg>std: Introduce a Runtime trait<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! The Rust Runtime, including the task scheduler and I/O

The `rt` module provides the private runtime infrastructure necessary
to support core language features like the exchange and local heap,
the garbage collector, logging, local data and unwinding. It also
implements the default task scheduler and task model. Initialization
routines are provided for setting up runtime resources in common
configurations, including that used by `rustc` when generating
executables.

It is intended that the features provided by `rt` can be factored in a
way such that the core library can be built with different 'profiles'
for different use cases, e.g. excluding the task scheduler. A number
of runtime features though are critical to the functioning of the
language and an implementation must be provided regardless of the
execution environment.

Of foremost importance is the global exchange heap, in the module
`global_heap`. Very little practical Rust code can be written without
access to the global heap. Unlike most of `rt` the global heap is
truly a global resource and generally operates independently of the
rest of the runtime.

All other runtime features are task-local, including the local heap,
the garbage collector, local storage, logging and the stack unwinder.

The relationship between `rt` and the rest of the core library is
not entirely clear yet and some modules will be moving into or
out of `rt` as development proceeds.

Several modules in `core` are clients of `rt`:

* `std::task` - The user-facing interface to the Rust task model.
* `std::task::local_data` - The interface to local data.
* `std::gc` - The garbage collector.
* `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`.
* `std::condition` - Uses local data.
* `std::cleanup` - Local heap destruction.
* `std::io` - In the future `std::io` will use an `rt` implementation.
* `std::logging`
* `std::pipes`
* `std::comm`
* `std::stackwalk`

*/

// XXX: this should not be here.
#[allow(missing_doc)];

use clone::Clone;
use container::Container;
use iter::Iterator;
use option::{Option, None, Some};
use ptr::RawPtr;
use rt::local::Local;
use rt::sched::{Scheduler, Shutdown};
use rt::sleeper_list::SleeperList;
use task::TaskResult;
use rt::task::{Task, SchedTask, GreenTask, Sched};
use send_str::SendStrStatic;
use unstable::atomics::{AtomicInt, AtomicBool, SeqCst};
use unstable::sync::UnsafeArc;
use vec::{OwnedVector, MutableVector, ImmutableVector};
use vec;

use self::thread::Thread;

// the os module needs to reach into this helper, so allow general access
// through this reexport.
pub use self::util::set_exit_status;

// this is somewhat useful when a program wants to spawn a "reasonable" number
// of workers based on the constraints of the system that it's running on.
// Perhaps this shouldn't be a `pub use` though and there should be another
// method...
pub use self::util::default_sched_threads;

// Re-export of the functionality in the kill module
pub use self::kill::BlockedTask;

// XXX: these probably shouldn't be public...
#[doc(hidden)]
pub mod shouldnt_be_public {
    pub use super::local_ptr::native::maybe_tls_key;
    #[cfg(not(windows), not(target_os = "android"))]
    pub use super::local_ptr::compiled::RT_TLS_PTR;
}

// Internal macros used by the runtime.
mod macros;

/// Basic implementation of an EventLoop, provides no I/O interfaces
mod basic;

/// The global (exchange) heap.
pub mod global_heap;

/// Implementations of language-critical runtime features like @.
pub mod task;

/// Facilities related to task failure, killing, and death.
mod kill;

/// The coroutine task scheduler, built on the `io` event loop.
pub mod sched;

/// The EventLoop and internal synchronous I/O interface.
pub mod rtio;

/// The Local trait for types that are accessible via thread-local
/// or task-local storage.
pub mod local;

/// A mostly lock-free multi-producer, single consumer queue.
pub mod mpsc_queue;

/// A lock-free single-producer, single consumer queue.
pub mod spsc_queue;

/// A lock-free multi-producer, multi-consumer bounded queue.
mod mpmc_bounded_queue;

/// A parallel work-stealing deque
pub mod deque;

/// A parallel data structure for tracking sleeping schedulers.
pub mod sleeper_list;

/// Stack segments and caching.
pub mod stack;

/// CPU context swapping.
mod context;

/// Bindings to system threading libraries.
pub mod thread;

/// The runtime configuration, read from environment variables.
pub mod env;

/// The local, managed heap
pub mod local_heap;

/// The Logger trait and implementations
pub mod logging;

/// Crate map
pub mod crate_map;

/// Tools for testing the runtime
pub mod test;

/// Reference counting
pub mod rc;

/// A simple single-threaded channel type for passing buffered data between
/// scheduler and task context
pub mod tube;

/// The runtime needs to be able to put a pointer into thread-local storage.
mod local_ptr;

/// Bindings to pthread/windows thread-local storage.
mod thread_local_storage;

/// Stack unwinding
pub mod unwind;

/// Just stuff
mod util;

// Global command line argument storage
pub mod args;

// Support for dynamic borrowck
pub mod borrowck;

/// The default error code of the rust runtime if the main task fails instead
/// of exiting cleanly.
pub static DEFAULT_ERROR_CODE: int = 101;

/// The interface to the current runtime.
///
/// This trait is used as the abstraction between 1:1 and M:N scheduling. The
/// two independent crates, libnative and libgreen, both have objects which
/// implement this trait. The goal of this trait is to encompass all the
/// fundamental differences in functionality between the 1:1 and M:N runtime
/// modes.
pub trait Runtime {
    // Necessary scheduling functions, used for channels and blocking I/O
    // (sometimes).
    fn yield_now(~self, cur_task: ~Task);
    fn maybe_yield(~self, cur_task: ~Task);
    fn deschedule(~self, times: uint, cur_task: ~Task,
                  f: |BlockedTask| -> Result<(), BlockedTask>);
    fn reawaken(~self, to_wake: ~Task, can_resched: bool);

    // Miscellaneous calls which are very different depending on what context
    // you're in.
    fn spawn_sibling(~self, cur_task: ~Task, opts: TaskOpts, f: proc());
    fn local_io<'a>(&'a mut self) -> Option<rtio::LocalIo<'a>>;

    // XXX: This is a serious code smell and this should not exist at all.
    fn wrap(~self) -> ~Any;
}

/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
/// the crate's logging flags, registering GC
/// metadata, and storing the process arguments.
pub fn init(argc: int, argv: **u8) {
    // XXX: Derefing these pointers is not safe.
    // Need to propagate the unsafety to `start`.
    unsafe {
        args::init(argc, argv);
        env::init();
        logging::init();
    }
}

/// One-time runtime cleanup.
///
/// This function is unsafe because it performs no checks to ensure that the
/// runtime has completely ceased running. It is the responsibility of the
/// caller to ensure that the runtime is entirely shut down and nothing will be
/// poking around at the internal components.
///
/// Invoking cleanup while portions of the runtime are still in use may cause
/// undefined behavior.
pub unsafe fn cleanup() {
    args::cleanup();
    local_ptr::cleanup();
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate plank_errors;
extern crate plank_syntax;
extern crate plank_frontend;
extern crate plank_ir;
extern crate plank_interpreter;

mod ast_printer;

use std::convert::From;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use plank_errors::Reporter;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    BuildFail,
    Interpreter(plank_interpreter::Error),
    InterpreterExit(i32),
}

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

impl From<plank_interpreter::Error> for Error {
    fn from(err: plank_interpreter::Error) -> Error {
        Error::Interpreter(err)
    }
}

#[derive(Debug)]
enum Command {
    Lex,
    Parse,
    EmitIr,
    Interpret,
}

#[derive(Debug)]
enum Stream {
    File(PathBuf),
    Std,
}

#[derive(Debug)]
struct Params {
    command: Command,
    input: Stream,
    output: Stream,
}

type Result<T> = ::std::result::Result<T, Error>;

fn main() {
    match run() {
        Ok(()) => {}
        Err(Error::BuildFail) => {
            eprintln!("error: build failed");
            ::std::process::exit(1);
        }
        Err(Error::Io(err)) => {
            eprintln!("IO error:\n{}", err);
            ::std::process::exit(1);
        }
        Err(Error::Interpreter(ref err)) => {
            eprintln!("Interpreter failed:\n{}", err);
            ::std::process::exit(1);
        }
        Err(Error::InterpreterExit(code)) => {
            eprintln!("Interpreter exited with status code {}", code);
            ::std::process::exit(code);
        }
    }
}

fn run() -> Result<()> {
    let params = parse_params()?;
    let input = read_input(&params.input)?;
    match params.output {
        Stream::Std => {
            let stdout = io::stdout();
            let stdout = stdout.lock();
            run_command(&input, &params.command, stdout)
        }
        Stream::File(ref name) => {
            let file = ::std::fs::File::create(name)?;
            run_command(&input, &params.command, file)
        }
    }
}

fn run_command<W: Write>(input: &str, command: &Command, output: W) -> Result<()> {
    match *command {
        Command::Lex => lex(input, output),
        Command::Parse => parse(input, output),
        Command::EmitIr => emit_ir(input, output),
        Command::Interpret => interpret(input, output),
    }
}

fn parse_params() -> Result<Params> {
    use clap::{App, Arg};

    let matches = App::new("Plank compiler")
        .arg(Arg::with_name("lex")
            .long("lex")
            .help("List tokens in input")
            .conflicts_with_all(&["parse", "emit-ir", "interpret"]))
        .arg(Arg::with_name("parse")
            .long("parse")
            .help("Parse input")
            .conflicts_with_all(&["lex", "emit-ir", "interpret"]))
        .arg(Arg::with_name("emit-ir")
            .long("emit-ir")
            .help("Emit plank IR")
            .conflicts_with_all(&["lex", "parse", "interpret"]))
        .arg(Arg::with_name("interpret")
            .long("interpret")
            .help("Compile to IR and interpret")
            .conflicts_with_all(&["lex", "parse", "emit-ir"]))
        .arg(Arg::with_name("input")
            .index(1)
            .help("Set input file, uses stdin if none provided"))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Set output file, uses stdout if none provided"))
        .get_matches();
    let default_command = Command::Interpret;
    let command = if matches.is_present("lex") {
        Command::Lex
    } else if matches.is_present("parse") {
        Command::Parse
    } else if matches.is_present("emit-ir") {
        Command::EmitIr
    } else if matches.is_present("interpret") {
        Command::Interpret
    } else {
        default_command
    };

    let input = match matches.value_of_os("input") {
        Some(path) => Stream::File(Path::new(path).to_owned()),
        None => Stream::Std,
    };

    let output = match matches.value_of_os("output") {
        Some(path) => Stream::File(Path::new(path).to_owned()),
        None => Stream::Std,
    };

    Ok(Params {
        command,
        input,
        output,
    })
}

fn read_file(name: &Path) -> Result<String> {
    use std::fs::File;
    let mut file = File::open(name)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn read_stdin() -> Result<String> {
    use std::io::prelude::*;
    let stdin = io::stdin();
    let mut stdin = stdin.lock();
    let mut input = String::new();
    stdin.read_to_string(&mut input)?;
    Ok(input)
}

fn read_input(stream: &Stream) -> Result<String> {
    match *stream {
        Stream::File(ref file) => read_file(file),
        Stream::Std => read_stdin(),
    }
}

fn emit_diagnostics(input: &str, reporter: Reporter) -> Result<()> {
    let mut diagnostics = reporter.get_diagnostics();
    diagnostics.sort_by_key(|d| d.primary_span.map(|s| s.start));
    plank_errors::print_diagnostics(&input, &diagnostics);
    if reporter.has_errors() {
        Err(Error::BuildFail)
    } else {
        Ok(())
    }
}

fn lex<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    emit_diagnostics(source, reporter)?;
    for tok in tokens {
        output.write_fmt(format_args!("{:?}\n", *tok))?;
    }
    Ok(())
}

fn parse<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let formatted = ast_printer::format_program(&program);
    output.write_all(formatted.as_bytes())?;
    output.write_all(b"\n")?;
    Ok(())
}

fn emit_ir<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    let ir = plank_frontend::compile(&program, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let mut ir = ir.expect("no errors but failed to produce IR");
    plank_ir::optimization::optimize(&mut ir);
    plank_ir::emit_program(&ir, &mut output)?;
    plank_ir::validate_ir(&ir);
    Ok(())
}

fn interpret<W: Write>(source: &str, output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    let ir = plank_frontend::compile(&program, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let ir = ir.expect("build succeeded but failed to produce IR");
    let input = io::empty();
    let exit_code = plank_interpreter::run_program(&ir, input, output)?;
    if exit_code == 0 {
        Ok(())
    } else {
        Err(Error::InterpreterExit(exit_code))
    }
}
<commit_msg>don't actually optimize anything yet<commit_after>extern crate clap;
extern crate plank_errors;
extern crate plank_syntax;
extern crate plank_frontend;
extern crate plank_ir;
extern crate plank_interpreter;

mod ast_printer;

use std::convert::From;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use plank_errors::Reporter;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    BuildFail,
    Interpreter(plank_interpreter::Error),
    InterpreterExit(i32),
}

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

impl From<plank_interpreter::Error> for Error {
    fn from(err: plank_interpreter::Error) -> Error {
        Error::Interpreter(err)
    }
}

#[derive(Debug)]
enum Command {
    Lex,
    Parse,
    EmitIr,
    Interpret,
}

#[derive(Debug)]
enum Stream {
    File(PathBuf),
    Std,
}

#[derive(Debug)]
struct Params {
    command: Command,
    input: Stream,
    output: Stream,
}

type Result<T> = ::std::result::Result<T, Error>;

fn main() {
    match run() {
        Ok(()) => {}
        Err(Error::BuildFail) => {
            eprintln!("error: build failed");
            ::std::process::exit(1);
        }
        Err(Error::Io(err)) => {
            eprintln!("IO error:\n{}", err);
            ::std::process::exit(1);
        }
        Err(Error::Interpreter(ref err)) => {
            eprintln!("Interpreter failed:\n{}", err);
            ::std::process::exit(1);
        }
        Err(Error::InterpreterExit(code)) => {
            eprintln!("Interpreter exited with status code {}", code);
            ::std::process::exit(code);
        }
    }
}

fn run() -> Result<()> {
    let params = parse_params()?;
    let input = read_input(&params.input)?;
    match params.output {
        Stream::Std => {
            let stdout = io::stdout();
            let stdout = stdout.lock();
            run_command(&input, &params.command, stdout)
        }
        Stream::File(ref name) => {
            let file = ::std::fs::File::create(name)?;
            run_command(&input, &params.command, file)
        }
    }
}

fn run_command<W: Write>(input: &str, command: &Command, output: W) -> Result<()> {
    match *command {
        Command::Lex => lex(input, output),
        Command::Parse => parse(input, output),
        Command::EmitIr => emit_ir(input, output),
        Command::Interpret => interpret(input, output),
    }
}

fn parse_params() -> Result<Params> {
    use clap::{App, Arg};

    let matches = App::new("Plank compiler")
        .arg(Arg::with_name("lex")
            .long("lex")
            .help("List tokens in input")
            .conflicts_with_all(&["parse", "emit-ir", "interpret"]))
        .arg(Arg::with_name("parse")
            .long("parse")
            .help("Parse input")
            .conflicts_with_all(&["lex", "emit-ir", "interpret"]))
        .arg(Arg::with_name("emit-ir")
            .long("emit-ir")
            .help("Emit plank IR")
            .conflicts_with_all(&["lex", "parse", "interpret"]))
        .arg(Arg::with_name("interpret")
            .long("interpret")
            .help("Compile to IR and interpret")
            .conflicts_with_all(&["lex", "parse", "emit-ir"]))
        .arg(Arg::with_name("input")
            .index(1)
            .help("Set input file, uses stdin if none provided"))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Set output file, uses stdout if none provided"))
        .get_matches();
    let default_command = Command::Interpret;
    let command = if matches.is_present("lex") {
        Command::Lex
    } else if matches.is_present("parse") {
        Command::Parse
    } else if matches.is_present("emit-ir") {
        Command::EmitIr
    } else if matches.is_present("interpret") {
        Command::Interpret
    } else {
        default_command
    };

    let input = match matches.value_of_os("input") {
        Some(path) => Stream::File(Path::new(path).to_owned()),
        None => Stream::Std,
    };

    let output = match matches.value_of_os("output") {
        Some(path) => Stream::File(Path::new(path).to_owned()),
        None => Stream::Std,
    };

    Ok(Params {
        command,
        input,
        output,
    })
}

fn read_file(name: &Path) -> Result<String> {
    use std::fs::File;
    let mut file = File::open(name)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn read_stdin() -> Result<String> {
    use std::io::prelude::*;
    let stdin = io::stdin();
    let mut stdin = stdin.lock();
    let mut input = String::new();
    stdin.read_to_string(&mut input)?;
    Ok(input)
}

fn read_input(stream: &Stream) -> Result<String> {
    match *stream {
        Stream::File(ref file) => read_file(file),
        Stream::Std => read_stdin(),
    }
}

fn emit_diagnostics(input: &str, reporter: Reporter) -> Result<()> {
    let mut diagnostics = reporter.get_diagnostics();
    diagnostics.sort_by_key(|d| d.primary_span.map(|s| s.start));
    plank_errors::print_diagnostics(&input, &diagnostics);
    if reporter.has_errors() {
        Err(Error::BuildFail)
    } else {
        Ok(())
    }
}

fn lex<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    emit_diagnostics(source, reporter)?;
    for tok in tokens {
        output.write_fmt(format_args!("{:?}\n", *tok))?;
    }
    Ok(())
}

fn parse<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let formatted = ast_printer::format_program(&program);
    output.write_all(formatted.as_bytes())?;
    output.write_all(b"\n")?;
    Ok(())
}

fn emit_ir<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    let ir = plank_frontend::compile(&program, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let mut ir = ir.expect("no errors but failed to produce IR");
    plank_ir::emit_program(&ir, &mut output)?;
    plank_ir::validate_ir(&ir);
    Ok(())
}

fn interpret<W: Write>(source: &str, output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    let ir = plank_frontend::compile(&program, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let ir = ir.expect("build succeeded but failed to produce IR");
    let input = io::empty();
    let exit_code = plank_interpreter::run_program(&ir, input, output)?;
    if exit_code == 0 {
        Ok(())
    } else {
        Err(Error::InterpreterExit(exit_code))
    }
}
<|endoftext|>


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

use base::ShareContext;
use context::GraphicsContextMethods;

use sync::Arc;
use geom::size::Size2D;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow};
use io_surface::{kIOSurfaceHeight, kIOSurfaceIsGlobal, kIOSurfaceWidth};
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext};
use opengles::cgl::{CGLSetCurrentContext, CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant};
use opengles::cgl::{kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER};
use opengles::gl2::{FRAMEBUFFER_COMPLETE, GLenum, GLint, GLsizei, GLuint, LINEAR};
use opengles::gl2::{NEAREST, RGBA, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};
use opengles::gl2;

use std::mem;
use std::ptr;

/// Mac-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
    cgl_context: Arc<CGLContextObj>,
}

impl GraphicsContext {
    /// Returns a new context, possibly shared with another context.
    fn new_possibly_shared(share_context: Option<GraphicsContext>) -> GraphicsContext {
        unsafe {
            // Choose a pixel format.
            let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
            let mut pixel_format = ptr::null();
            let mut pixel_format_count = 1;
            let gl_error = CGLChoosePixelFormat(mem::transmute(&attributes[0]),
                                                &mut pixel_format,
                                                &mut pixel_format_count);
            assert!(gl_error == kCGLNoError);

            // Create the context.
            let cgl_context = ptr::null();
            let gl_error = match share_context {
                None => CGLCreateContext(pixel_format, ptr::null(), &cgl_context),
                Some(ref share_context) => {
                    let native = share_context.native();
                    CGLCreateContext(pixel_format, *native, &cgl_context)
                }
            };
            assert!(gl_error == kCGLNoError);

            GraphicsContextMethods::wrap(Arc::new(cgl_context))
        }
    }
}

impl GraphicsContextMethods<CGLContextObj> for GraphicsContext {
    /// Wraps the given instance of the native Core OpenGL graphics context.
    fn wrap(instance: Arc<CGLContextObj>) -> GraphicsContext {
        GraphicsContext {
            cgl_context: instance
        }
    }

    /// Returns the underlying native 3D context without modifying its reference count.
    fn native(&self) -> Arc<CGLContextObj> {
        self.cgl_context.clone()
    }

    /// Creates a new offscreen 3D graphics context.
    fn new() -> GraphicsContext {
        GraphicsContext::new_possibly_shared(None)
    }

    /// Creates a new offscreen 3D graphics context shared with the given context.
    fn new_shared(share_context: GraphicsContext) -> GraphicsContext {
        GraphicsContext::new_possibly_shared(Some(share_context))
    }

    /// Makes this context the current context.
    fn make_current(&self) {
        unsafe {
            let gl_error = CGLSetCurrentContext(*self.cgl_context);
            assert!(gl_error == kCGLNoError)
        }
    }
}

impl Clone for GraphicsContext {
    fn clone(&self) -> GraphicsContext {
        GraphicsContextMethods::wrap(self.native())
    }
}

pub struct Context {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> GraphicsContext {
    let context: GraphicsContext = GraphicsContextMethods::new();
    context.make_current();
    context
}

pub fn init_surface(size: Size2D<int>) -> IOSurface {
    use core_foundation::boolean::CFBoolean;
    use core_foundation::string::CFString;
    use core_foundation::number::CFNumber;
    use core_foundation::dictionary::CFDictionary;
    use core_foundation::base::{CFType, TCFType};
    use io_surface;

    // TODO: dictionary constructor should be less ridiculous.
    // Or, we could add bindings for mutable dictionaries.
    let k_width: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceWidth) };
    let v_width: CFNumber = FromPrimitive::from_i32(size.width as i32).unwrap();

    let k_height: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceHeight) };
    let v_height: CFNumber = FromPrimitive::from_i32(size.height as i32).unwrap();

    let k_bytes_per_row: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceBytesPerRow) };
    let v_bytes_per_row: CFNumber = FromPrimitive::from_i32(size.width as i32 * 4).unwrap();

    let k_bytes_per_elem: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceBytesPerElement) };
    let v_bytes_per_elem: CFNumber = FromPrimitive::from_i32(4i32).unwrap();

    let k_is_global: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceIsGlobal) };
    let v_is_global = CFBoolean::true_value();

    let pairs: Vec<(CFType, CFType)> = vec!(
        (k_width.as_CFType(), v_width.as_CFType()),
        (k_height.as_CFType(), v_height.as_CFType()),
        (k_bytes_per_row.as_CFType(), v_bytes_per_row.as_CFType()),
        (k_bytes_per_elem.as_CFType(), v_bytes_per_elem.as_CFType()),
        (k_is_global.as_CFType(), v_is_global.as_CFType()),
    );

    io_surface::new(&CFDictionary::from_CFType_pairs(pairs))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = *gl2::gen_textures(1).get(0);
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &GraphicsContext, surface: &IOSurface, size: Size2D<int>) {
    use core_foundation::base::TCFType;
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let native = context.native();
        let gl_error = CGLTexImageIOSurface2D(*native,
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              mem::transmute(surface.as_concrete_TypeRef()),
                                              0);
        assert!(gl_error == kCGLNoError);
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert!(gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE);
}

impl ShareContext for Context {
    fn new(size: Size2D<int>) -> Context {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(size.clone());

        // Create a framebuffer.
        let framebuffer = *gl2::gen_framebuffers(1).get(0);
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        Context {
            surface: surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id(&self) -> int {
        self.surface.get_id() as int
    }
}

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

use base::ShareContext;
use context::GraphicsContextMethods;

use sync::Arc;
use geom::size::Size2D;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow};
use io_surface::{kIOSurfaceHeight, kIOSurfaceIsGlobal, kIOSurfaceWidth};
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext};
use opengles::cgl::{CGLSetCurrentContext, CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant};
use opengles::cgl::{kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER};
use opengles::gl2::{FRAMEBUFFER_COMPLETE, GLenum, GLint, GLsizei, GLuint, LINEAR};
use opengles::gl2::{NEAREST, RGBA, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};
use opengles::gl2;

use std::mem;
use std::ptr;

/// Mac-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
    cgl_context: Arc<CGLContextObj>,
}

impl GraphicsContext {
    /// Returns a new context, possibly shared with another context.
    fn new_possibly_shared(share_context: Option<GraphicsContext>) -> GraphicsContext {
        unsafe {
            // Choose a pixel format.
            let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
            let mut pixel_format = ptr::null();
            let mut pixel_format_count = 1;
            let gl_error = CGLChoosePixelFormat(mem::transmute(&attributes[0]),
                                                &mut pixel_format,
                                                &mut pixel_format_count);
            assert!(gl_error == kCGLNoError);

            // Create the context.
            let cgl_context = ptr::null();
            let gl_error = match share_context {
                None => CGLCreateContext(pixel_format, ptr::null(), &cgl_context),
                Some(ref share_context) => {
                    let native = share_context.native();
                    CGLCreateContext(pixel_format, *native, &cgl_context)
                }
            };
            assert!(gl_error == kCGLNoError);

            GraphicsContextMethods::wrap(Arc::new(cgl_context))
        }
    }
}

impl GraphicsContextMethods<CGLContextObj> for GraphicsContext {
    /// Wraps the given instance of the native Core OpenGL graphics context.
    fn wrap(instance: Arc<CGLContextObj>) -> GraphicsContext {
        GraphicsContext {
            cgl_context: instance
        }
    }

    /// Returns the underlying native 3D context without modifying its reference count.
    fn native(&self) -> Arc<CGLContextObj> {
        self.cgl_context.clone()
    }

    /// Creates a new offscreen 3D graphics context.
    fn new() -> GraphicsContext {
        GraphicsContext::new_possibly_shared(None)
    }

    /// Creates a new offscreen 3D graphics context shared with the given context.
    fn new_shared(share_context: GraphicsContext) -> GraphicsContext {
        GraphicsContext::new_possibly_shared(Some(share_context))
    }

    /// Makes this context the current context.
    fn make_current(&self) {
        unsafe {
            let gl_error = CGLSetCurrentContext(*self.cgl_context);
            assert!(gl_error == kCGLNoError)
        }
    }
}

impl Clone for GraphicsContext {
    fn clone(&self) -> GraphicsContext {
        GraphicsContextMethods::wrap(self.native())
    }
}

pub struct Context {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> GraphicsContext {
    let context: GraphicsContext = GraphicsContextMethods::new();
    context.make_current();
    context
}

pub fn init_surface(size: Size2D<int>) -> IOSurface {
    use core_foundation::boolean::CFBoolean;
    use core_foundation::string::CFString;
    use core_foundation::number::CFNumber;
    use core_foundation::dictionary::CFDictionary;
    use core_foundation::base::{CFType, TCFType};
    use io_surface;

    // TODO: dictionary constructor should be less ridiculous.
    // Or, we could add bindings for mutable dictionaries.
    let k_width: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceWidth) };
    let v_width: CFNumber = FromPrimitive::from_i32(size.width as i32).unwrap();

    let k_height: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceHeight) };
    let v_height: CFNumber = FromPrimitive::from_i32(size.height as i32).unwrap();

    let k_bytes_per_row: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceBytesPerRow) };
    let v_bytes_per_row: CFNumber = FromPrimitive::from_i32(size.width as i32 * 4).unwrap();

    let k_bytes_per_elem: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceBytesPerElement) };
    let v_bytes_per_elem: CFNumber = FromPrimitive::from_i32(4i32).unwrap();

    let k_is_global: CFString = unsafe { TCFType::wrap_under_get_rule(kIOSurfaceIsGlobal) };
    let v_is_global = CFBoolean::true_value();

    let pairs: Vec<(CFType, CFType)> = vec!(
        (k_width.as_CFType(), v_width.as_CFType()),
        (k_height.as_CFType(), v_height.as_CFType()),
        (k_bytes_per_row.as_CFType(), v_bytes_per_row.as_CFType()),
        (k_bytes_per_elem.as_CFType(), v_bytes_per_elem.as_CFType()),
        (k_is_global.as_CFType(), v_is_global.as_CFType()),
    );

    io_surface::new(&CFDictionary::from_CFType_pairs(pairs.as_slice()))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = *gl2::gen_textures(1).get(0);
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &GraphicsContext, surface: &IOSurface, size: Size2D<int>) {
    use core_foundation::base::TCFType;
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let native = context.native();
        let gl_error = CGLTexImageIOSurface2D(*native,
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              mem::transmute(surface.as_concrete_TypeRef()),
                                              0);
        assert!(gl_error == kCGLNoError);
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert!(gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE);
}

impl ShareContext for Context {
    fn new(size: Size2D<int>) -> Context {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(size.clone());

        // Create a framebuffer.
        let framebuffer = *gl2::gen_framebuffers(1).get(0);
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        Context {
            surface: surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id(&self) -> int {
        self.surface.get_id() as int
    }
}

<|endoftext|>