<commit_before>use mod azure::azure_hl;

use au = gfx::geometry;
use au::au;
use azure::bindgen::AzDrawTargetFillGlyphs;
use azure::cairo::{cairo_font_face_t, cairo_scaled_font_t};
use azure::cairo_hl::ImageSurface;
use azure::{AzDrawOptions, AzFloat, AzGlyph, AzGlyphBuffer};
use azure_hl::{AsAzureRect, B8G8R8A8, Color, ColorPattern, DrawOptions, DrawSurfaceOptions};
use azure_hl::{DrawTarget, Linear};
use comm::*;
use compositor::Compositor;
use core::dvec::DVec;
use dl = display_list;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use mod gfx::render_layers;
use gfx::render_layers::RenderLayer;
use image::base::Image;
use libc::size_t;
use pipes::{Port, Chan};
use platform::osmain;
use ptr::to_unsafe_ptr;
use std::arc::ARC;
use std::cell::Cell;
use text::text_run::TextRun;
use text::font::Font;
use text::font_cache::FontCache;

pub type Renderer = comm::Chan<Msg>;

pub enum Msg {
    RenderMsg(RenderLayer),
    ExitMsg(pipes::Chan<()>)
}

struct LayerBuffer {
    // TODO: We should not be coupled to Cairo this tightly. Instead we should pull the buffer out
    // of the draw target with the Azure API.
    cairo_surface: ImageSurface,

    draw_target: DrawTarget,
    size: Size2D<uint>
}

struct RenderContext {
    canvas: &LayerBuffer,
    font_cache: @FontCache,
}

pub type RenderTask = comm::Chan<Msg>;

pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
    do task::spawn_listener |po: comm::Port<Msg>| {
        let (layer_buffer_channel, layer_buffer_port) = pipes::stream();
        let mut layer_buffer_channel = layer_buffer_channel;
        let mut layer_buffer_port = layer_buffer_port;

        let font_cache = FontCache();

        debug!("renderer: beginning rendering loop");

        compositor.begin_drawing(move layer_buffer_channel);

        loop {
            match po.recv() {
                RenderMsg(move render_layer) => {
                    debug!("renderer: got render request");

                    if !layer_buffer_port.peek() {
                        warn!("renderer: no layer buffer. skipping frame");
                        loop;
                    }

                    let layer_buffer_cell = Cell(layer_buffer_port.recv());

                    let (layer_buffer_channel, new_layer_buffer_port) = pipes::stream();
                    let layer_buffer_channel = Cell(move layer_buffer_channel);
                    layer_buffer_port = new_layer_buffer_port;

                    let render_layer = Cell(move render_layer);

                    #debug("renderer: rendering");

                    do util::time::time(~"rendering") {
                        let layer_buffer = layer_buffer_cell.take();
                        let render_layer = move render_layer.take();

                        let layer_buffer =
                                for render_layers::render_layers(&render_layer, move layer_buffer)
                                |render_layer, layer_buffer| {
                            let ctx = RenderContext {
                                canvas: layer_buffer,
                                font_cache: font_cache
                            };

                            clear(&ctx);
                            render_layer.display_list.draw(&ctx);
                        };

                        #debug("renderer: returning surface");
                        compositor.draw(layer_buffer_channel.take(), move layer_buffer);
                    }
                }
                ExitMsg(response_ch) => {
                    response_ch.send(());
                    break;
                }
            }
        }
    }
}

trait to_float {
    fn to_float() -> float;
}

impl u8 : to_float {
    fn to_float() -> float {
        (self as float) / 255f
    }
}

trait ToAzureRect {
    fn to_azure_rect() -> Rect<AzFloat>;
}

impl Rect<au> : ToAzureRect {
    fn to_azure_rect() -> Rect<AzFloat> {
        Rect(Point2D(au::to_px(self.origin.x) as AzFloat, au::to_px(self.origin.y) as AzFloat),
             Size2D(au::to_px(self.size.width) as AzFloat, au::to_px(self.size.height) as AzFloat))
    }
}

pub fn draw_solid_color(ctx: &RenderContext, bounds: &Rect<au>, r: u8, g: u8, b: u8) {
    let color = Color(r.to_float() as AzFloat,
                      g.to_float() as AzFloat,
                      b.to_float() as AzFloat,
                      1f as AzFloat);

    ctx.canvas.draw_target.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color));
}

pub fn draw_image(ctx: &RenderContext, bounds: Rect<au>, image: ARC<~Image>) {
    let image = std::arc::get(&image);
    let size = Size2D(image.width as i32, image.height as i32);
    let stride = image.width * 4;

    let draw_target_ref = &ctx.canvas.draw_target;
    let azure_surface = draw_target_ref.create_source_surface_from_data(image.data, size,
                                                                        stride as i32, B8G8R8A8);
    let source_rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
                           Size2D(image.width as AzFloat, image.height as AzFloat));
    let dest_rect = bounds.to_azure_rect();
    let draw_surface_options = DrawSurfaceOptions(Linear, true);
    let draw_options = DrawOptions(1.0f as AzFloat, 0);
    draw_target_ref.draw_surface(azure_surface, dest_rect, source_rect, draw_surface_options,
                                 draw_options);
}

pub fn draw_text(ctx: &RenderContext, bounds: Rect<au>, run: &TextRun, offset: uint, length: uint) {
    use ptr::{null};
    use vec::raw::to_ptr;
    use libc::types::common::c99::{uint16_t, uint32_t};
    use geom::point::Point2D;
    use text::font_cache::FontCache;
    use text::font::Font;
    use azure::{AzNativeFont, AzFloat, AZ_NATIVE_FONT_CAIRO_FONT_FACE};
    use azure::bindgen::{AzCreateScaledFontWithCairo,
                            AzReleaseScaledFont,
                            AzCreateColorPattern,
                            AzReleaseColorPattern};
    use azure::cairo::bindgen::cairo_scaled_font_destroy;

    // FIXME: font should be accessible from TextRun
    let font = ctx.font_cache.get_test_font();

    let nfont: AzNativeFont = {
        mType: AZ_NATIVE_FONT_CAIRO_FONT_FACE,
        mFont: null()
    };

    let cfont = get_cairo_font(font);
    let azfont = AzCreateScaledFontWithCairo(to_unsafe_ptr(&nfont), 1f as AzFloat, cfont);
    assert azfont.is_not_null();
    cairo_scaled_font_destroy(cfont);

    let color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let pattern = AzCreateColorPattern(to_unsafe_ptr(&color));
    assert pattern.is_not_null();

    let options: AzDrawOptions = {
        mAlpha: 1f as AzFloat,
        fields: 0 as uint16_t
    };

    let mut origin = Point2D(bounds.origin.x, bounds.origin.y.add(&bounds.size.height));
    let azglyphs = DVec();
    azglyphs.reserve(length);

    do run.glyphs.iter_glyphs_for_range(offset, length) |_i, glyph| {
        let glyph_advance = glyph.advance();
        let glyph_offset = glyph.offset().get_default(au::zero_point());

        let azglyph: AzGlyph = {
            mIndex: glyph.index() as uint32_t,
            mPosition: {
                x: au::to_px(origin.x + glyph_offset.x) as AzFloat,
                y: au::to_px(origin.y + glyph_offset.y) as AzFloat
            }
        };
        origin = Point2D(origin.x + glyph_advance, origin.y);
        azglyphs.push(move azglyph)
    };

    let azglyph_buf_len = azglyphs.len();
    let azglyph_buf = dvec::unwrap(move azglyphs);
    let glyphbuf: AzGlyphBuffer = unsafe {{
        mGlyphs: to_ptr(azglyph_buf),
        mNumGlyphs: azglyph_buf_len as uint32_t
    }};

    // TODO: this call needs to move into azure_hl.rs
    AzDrawTargetFillGlyphs(ctx.canvas.draw_target.azure_draw_target, azfont,
                           to_unsafe_ptr(&glyphbuf), pattern, to_unsafe_ptr(&options), null());

    AzReleaseColorPattern(pattern);
    AzReleaseScaledFont(azfont);
}

#[cfg(target_os = "linux")]
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {

    use libc::c_int;
    use azure::cairo_ft::bindgen::{cairo_ft_font_face_create_for_ft_face};

    let ftface = font.native_font.face;
    let cface = cairo_ft_font_face_create_for_ft_face(ftface, 0 as c_int);
    // FIXME: error handling
    return cface;
}

#[cfg(target_os = "macos")]
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {
    use azure::cairo_quartz::bindgen::cairo_quartz_font_face_create_for_cgfont;

    let cgfont = font.native_font.cgfont;
    let face = cairo_quartz_font_face_create_for_cgfont(cgfont);
    // FIXME: error handling
    return face;
}

fn get_cairo_font(font: &Font) -> *cairo_scaled_font_t {

    use libc::c_double;
    use azure::cairo;
    use cairo::cairo_matrix_t;
    use cairo::bindgen::{cairo_matrix_init_identity,
                         cairo_matrix_scale,
                         cairo_font_options_create,
                         cairo_scaled_font_create,
                         cairo_font_options_destroy,
                         cairo_font_face_destroy};

    // FIXME: error handling

    let face = get_cairo_face(font);

    let idmatrix: cairo_matrix_t = {
        xx: 0 as c_double,
        yx: 0 as c_double,
        xy: 0 as c_double,
        yy: 0 as c_double,
        x0: 0 as c_double,
        y0: 0 as c_double
    };
    cairo_matrix_init_identity(to_unsafe_ptr(&idmatrix));

    let fontmatrix = idmatrix;
    cairo_matrix_scale(to_unsafe_ptr(&fontmatrix), 20f as c_double, 20f as c_double);
    let options = cairo_font_options_create();
    let cfont = cairo_scaled_font_create(face, to_unsafe_ptr(&fontmatrix),
                                         to_unsafe_ptr(&idmatrix), options);
    cairo_font_options_destroy(options);
    cairo_font_face_destroy(face);

    return cfont;
}

fn clear(ctx: &RenderContext) {
    let pattern = ColorPattern(Color(1f as AzFloat, 1f as AzFloat, 1f as AzFloat, 1f as AzFloat));
    let rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
                    Size2D(ctx.canvas.size.width as AzFloat, ctx.canvas.size.height as AzFloat));
    ctx.canvas.draw_target.fill_rect(&rect, &pattern);
}
<commit_msg>Renderer can't just skip frames<commit_after>use mod azure::azure_hl;

use au = gfx::geometry;
use au::au;
use azure::bindgen::AzDrawTargetFillGlyphs;
use azure::cairo::{cairo_font_face_t, cairo_scaled_font_t};
use azure::cairo_hl::ImageSurface;
use azure::{AzDrawOptions, AzFloat, AzGlyph, AzGlyphBuffer};
use azure_hl::{AsAzureRect, B8G8R8A8, Color, ColorPattern, DrawOptions, DrawSurfaceOptions};
use azure_hl::{DrawTarget, Linear};
use comm::*;
use compositor::Compositor;
use core::dvec::DVec;
use dl = display_list;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use mod gfx::render_layers;
use gfx::render_layers::RenderLayer;
use image::base::Image;
use libc::size_t;
use pipes::{Port, Chan};
use platform::osmain;
use ptr::to_unsafe_ptr;
use std::arc::ARC;
use std::cell::Cell;
use text::text_run::TextRun;
use text::font::Font;
use text::font_cache::FontCache;

pub type Renderer = comm::Chan<Msg>;

pub enum Msg {
    RenderMsg(RenderLayer),
    ExitMsg(pipes::Chan<()>)
}

struct LayerBuffer {
    // TODO: We should not be coupled to Cairo this tightly. Instead we should pull the buffer out
    // of the draw target with the Azure API.
    cairo_surface: ImageSurface,

    draw_target: DrawTarget,
    size: Size2D<uint>
}

struct RenderContext {
    canvas: &LayerBuffer,
    font_cache: @FontCache,
}

pub type RenderTask = comm::Chan<Msg>;

pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
    do task::spawn_listener |po: comm::Port<Msg>| {
        let (layer_buffer_channel, layer_buffer_port) = pipes::stream();
        let mut layer_buffer_channel = layer_buffer_channel;
        let mut layer_buffer_port = layer_buffer_port;

        let font_cache = FontCache();

        debug!("renderer: beginning rendering loop");

        compositor.begin_drawing(move layer_buffer_channel);

        loop {
            match po.recv() {
                RenderMsg(move render_layer) => {
                    debug!("renderer: got render request");

                    if !layer_buffer_port.peek() {
                        warn!("renderer: waiting on layer buffer");
                    }

                    let layer_buffer_cell = Cell(layer_buffer_port.recv());

                    let (layer_buffer_channel, new_layer_buffer_port) = pipes::stream();
                    let layer_buffer_channel = Cell(move layer_buffer_channel);
                    layer_buffer_port = new_layer_buffer_port;

                    let render_layer = Cell(move render_layer);

                    #debug("renderer: rendering");

                    do util::time::time(~"rendering") {
                        let layer_buffer = layer_buffer_cell.take();
                        let render_layer = move render_layer.take();

                        let layer_buffer =
                                for render_layers::render_layers(&render_layer, move layer_buffer)
                                |render_layer, layer_buffer| {
                            let ctx = RenderContext {
                                canvas: layer_buffer,
                                font_cache: font_cache
                            };

                            clear(&ctx);
                            render_layer.display_list.draw(&ctx);
                        };

                        #debug("renderer: returning surface");
                        compositor.draw(layer_buffer_channel.take(), move layer_buffer);
                    }
                }
                ExitMsg(response_ch) => {
                    response_ch.send(());
                    break;
                }
            }
        }
    }
}

trait to_float {
    fn to_float() -> float;
}

impl u8 : to_float {
    fn to_float() -> float {
        (self as float) / 255f
    }
}

trait ToAzureRect {
    fn to_azure_rect() -> Rect<AzFloat>;
}

impl Rect<au> : ToAzureRect {
    fn to_azure_rect() -> Rect<AzFloat> {
        Rect(Point2D(au::to_px(self.origin.x) as AzFloat, au::to_px(self.origin.y) as AzFloat),
             Size2D(au::to_px(self.size.width) as AzFloat, au::to_px(self.size.height) as AzFloat))
    }
}

pub fn draw_solid_color(ctx: &RenderContext, bounds: &Rect<au>, r: u8, g: u8, b: u8) {
    let color = Color(r.to_float() as AzFloat,
                      g.to_float() as AzFloat,
                      b.to_float() as AzFloat,
                      1f as AzFloat);

    ctx.canvas.draw_target.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color));
}

pub fn draw_image(ctx: &RenderContext, bounds: Rect<au>, image: ARC<~Image>) {
    let image = std::arc::get(&image);
    let size = Size2D(image.width as i32, image.height as i32);
    let stride = image.width * 4;

    let draw_target_ref = &ctx.canvas.draw_target;
    let azure_surface = draw_target_ref.create_source_surface_from_data(image.data, size,
                                                                        stride as i32, B8G8R8A8);
    let source_rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
                           Size2D(image.width as AzFloat, image.height as AzFloat));
    let dest_rect = bounds.to_azure_rect();
    let draw_surface_options = DrawSurfaceOptions(Linear, true);
    let draw_options = DrawOptions(1.0f as AzFloat, 0);
    draw_target_ref.draw_surface(azure_surface, dest_rect, source_rect, draw_surface_options,
                                 draw_options);
}

pub fn draw_text(ctx: &RenderContext, bounds: Rect<au>, run: &TextRun, offset: uint, length: uint) {
    use ptr::{null};
    use vec::raw::to_ptr;
    use libc::types::common::c99::{uint16_t, uint32_t};
    use geom::point::Point2D;
    use text::font_cache::FontCache;
    use text::font::Font;
    use azure::{AzNativeFont, AzFloat, AZ_NATIVE_FONT_CAIRO_FONT_FACE};
    use azure::bindgen::{AzCreateScaledFontWithCairo,
                            AzReleaseScaledFont,
                            AzCreateColorPattern,
                            AzReleaseColorPattern};
    use azure::cairo::bindgen::cairo_scaled_font_destroy;

    // FIXME: font should be accessible from TextRun
    let font = ctx.font_cache.get_test_font();

    let nfont: AzNativeFont = {
        mType: AZ_NATIVE_FONT_CAIRO_FONT_FACE,
        mFont: null()
    };

    let cfont = get_cairo_font(font);
    let azfont = AzCreateScaledFontWithCairo(to_unsafe_ptr(&nfont), 1f as AzFloat, cfont);
    assert azfont.is_not_null();
    cairo_scaled_font_destroy(cfont);

    let color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let pattern = AzCreateColorPattern(to_unsafe_ptr(&color));
    assert pattern.is_not_null();

    let options: AzDrawOptions = {
        mAlpha: 1f as AzFloat,
        fields: 0 as uint16_t
    };

    let mut origin = Point2D(bounds.origin.x, bounds.origin.y.add(&bounds.size.height));
    let azglyphs = DVec();
    azglyphs.reserve(length);

    do run.glyphs.iter_glyphs_for_range(offset, length) |_i, glyph| {
        let glyph_advance = glyph.advance();
        let glyph_offset = glyph.offset().get_default(au::zero_point());

        let azglyph: AzGlyph = {
            mIndex: glyph.index() as uint32_t,
            mPosition: {
                x: au::to_px(origin.x + glyph_offset.x) as AzFloat,
                y: au::to_px(origin.y + glyph_offset.y) as AzFloat
            }
        };
        origin = Point2D(origin.x + glyph_advance, origin.y);
        azglyphs.push(move azglyph)
    };

    let azglyph_buf_len = azglyphs.len();
    let azglyph_buf = dvec::unwrap(move azglyphs);
    let glyphbuf: AzGlyphBuffer = unsafe {{
        mGlyphs: to_ptr(azglyph_buf),
        mNumGlyphs: azglyph_buf_len as uint32_t
    }};

    // TODO: this call needs to move into azure_hl.rs
    AzDrawTargetFillGlyphs(ctx.canvas.draw_target.azure_draw_target, azfont,
                           to_unsafe_ptr(&glyphbuf), pattern, to_unsafe_ptr(&options), null());

    AzReleaseColorPattern(pattern);
    AzReleaseScaledFont(azfont);
}

#[cfg(target_os = "linux")]
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {

    use libc::c_int;
    use azure::cairo_ft::bindgen::{cairo_ft_font_face_create_for_ft_face};

    let ftface = font.native_font.face;
    let cface = cairo_ft_font_face_create_for_ft_face(ftface, 0 as c_int);
    // FIXME: error handling
    return cface;
}

#[cfg(target_os = "macos")]
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {
    use azure::cairo_quartz::bindgen::cairo_quartz_font_face_create_for_cgfont;

    let cgfont = font.native_font.cgfont;
    let face = cairo_quartz_font_face_create_for_cgfont(cgfont);
    // FIXME: error handling
    return face;
}

fn get_cairo_font(font: &Font) -> *cairo_scaled_font_t {

    use libc::c_double;
    use azure::cairo;
    use cairo::cairo_matrix_t;
    use cairo::bindgen::{cairo_matrix_init_identity,
                         cairo_matrix_scale,
                         cairo_font_options_create,
                         cairo_scaled_font_create,
                         cairo_font_options_destroy,
                         cairo_font_face_destroy};

    // FIXME: error handling

    let face = get_cairo_face(font);

    let idmatrix: cairo_matrix_t = {
        xx: 0 as c_double,
        yx: 0 as c_double,
        xy: 0 as c_double,
        yy: 0 as c_double,
        x0: 0 as c_double,
        y0: 0 as c_double
    };
    cairo_matrix_init_identity(to_unsafe_ptr(&idmatrix));

    let fontmatrix = idmatrix;
    cairo_matrix_scale(to_unsafe_ptr(&fontmatrix), 20f as c_double, 20f as c_double);
    let options = cairo_font_options_create();
    let cfont = cairo_scaled_font_create(face, to_unsafe_ptr(&fontmatrix),
                                         to_unsafe_ptr(&idmatrix), options);
    cairo_font_options_destroy(options);
    cairo_font_face_destroy(face);

    return cfont;
}

fn clear(ctx: &RenderContext) {
    let pattern = ColorPattern(Color(1f as AzFloat, 1f as AzFloat, 1f as AzFloat, 1f as AzFloat));
    let rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
                    Size2D(ctx.canvas.size.width as AzFloat, ctx.canvas.size.height as AzFloat));
    ctx.canvas.draw_target.fill_rect(&rect, &pattern);
}
<|endoftext|>


<commit_before>use ShareGlContext = sharegl::platform::Context;
use azure::azure_hl;
use azure::azure_hl::DrawTarget;
use cairo::cairo_hl::ImageSurface;
use cairo::cairo_surface_t;
use core::util::replace;
use dom::event::{Event, ResizeEvent};
use dvec::DVec;
use geom::matrix::{Matrix4, identity};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::compositor::{Compositor, LayerBuffer, LayerBufferSet};
use layers::ImageLayer;
use pipes::Chan;
use resize_rate_limiter::ResizeRateLimiter;
use std::cell::Cell;
use std::cmp::FuzzyEq;
use task::TaskBuilder;
use vec::push;

pub type OSMain = comm::Chan<Msg>;

// FIXME: Move me over to opts.rs.
enum Mode {
	GlutMode,
	ShareMode
}

enum Window {
	GlutWindow(glut::Window),
	ShareWindow(ShareGlContext)
}

pub enum Msg {
    BeginDrawing(pipes::Chan<LayerBufferSet>),
    Draw(pipes::Chan<LayerBufferSet>, LayerBufferSet),
    AddKeyHandler(pipes::Chan<()>),
    Exit
}

fn OSMain(dom_event_chan: pipes::SharedChan<Event>) -> OSMain {
    let dom_event_chan = Cell(move dom_event_chan);
    do on_osmain::<Msg> |po, move dom_event_chan| {
        do platform::runmain {
            #debug("preparing to enter main loop");

            // FIXME: Use the servo options.
			let mode;
			match os::getenv("SERVO_SHARE") {
				Some(_) => mode = ShareMode,
				None => mode = GlutMode
			}

	        mainloop(mode, po, dom_event_chan.take());
        }
    }
}

/// Cairo surface wrapping to work with layers
struct CairoSurfaceImageData {
    cairo_surface: ImageSurface,
    size: Size2D<uint>
}

impl CairoSurfaceImageData : layers::layers::ImageData {
    fn size() -> Size2D<uint> { self.size }
    fn stride() -> uint { self.cairo_surface.width() as uint }
    fn format() -> layers::layers::Format { layers::layers::ARGB32Format }
    fn with_data(f: layers::layers::WithDataFn) { f(self.cairo_surface.data()) }
}

fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<Event>) {

    let key_handlers: @DVec<pipes::Chan<()>> = @DVec();

	let window;
	match mode {
		GlutMode => {
			glut::init();
			glut::init_display_mode(glut::DOUBLE);
			let glut_window = glut::create_window(~"Servo");
			glut::reshape_window(glut_window, 800, 600);
			window = GlutWindow(move glut_window);
		}
		ShareMode => {
			let share_context: ShareGlContext = sharegl::base::new(Size2D(800, 600));
			io::println(fmt!("Sharing ID is %d", share_context.id()));
			window = ShareWindow(move share_context);
		}
	}

    let surfaces = @SurfaceSet();

    let context = layers::rendergl::init_render_context();

    let image_data = @layers::layers::BasicImageData::new(
        Size2D(0u, 0u), 0, layers::layers::RGB24Format, ~[]);
    let image = @layers::layers::Image::new(image_data as @layers::layers::ImageData);
    let image_layer = @layers::layers::ImageLayer(image);
    let original_layer_transform = image_layer.common.transform;
    image_layer.common.set_transform(original_layer_transform.scale(&800.0f32, &600.0f32, &1f32));

    let scene = @layers::scene::Scene(layers::layers::ImageLayerKind(image_layer),
                                      Size2D(800.0f32, 600.0f32),
                                      identity(0.0f32));

    let done = @mut false;
    let resize_rate_limiter = @ResizeRateLimiter(move dom_event_chan);
    let check_for_messages = fn@() {

        // Periodically check if content responded to our last resize event
        resize_rate_limiter.check_resize_response();

        // Handle messages
        #debug("osmain: peeking");
        while po.peek() {
            match po.recv() {
                AddKeyHandler(move key_ch) => key_handlers.push(move key_ch),
                BeginDrawing(move sender) => lend_surface(surfaces, move sender),
                Draw(move sender, move dt) => {
                    #debug("osmain: received new frame");
                    return_surface(surfaces, move dt);
                    lend_surface(surfaces, move sender);

                    let buffers = &mut surfaces.front.layer_buffer_set.buffers;
                    let width = buffers[0].rect.size.width as uint;
                    let height = buffers[0].rect.size.height as uint;

                    let image_data = @CairoSurfaceImageData {
                        cairo_surface: buffers[0].cairo_surface.clone(),
                        size: Size2D(width, height)
                    };
                    let image = @layers::layers::Image::new(
                        image_data as @layers::layers::ImageData);

                    image_layer.set_image(image);
                    image_layer.common.set_transform(original_layer_transform.scale(
                        &(width as f32), &(height as f32), &1.0f32));
                }
                Exit => {
                    *done = true;
                }
            }
        }
    };

    let adjust_for_window_resizing: fn@() = || {
        let window_width = glut::get(glut::WindowWidth) as uint;
        let window_height = glut::get(glut::WindowHeight) as uint;

        // FIXME: Cross-crate struct mutability is broken.
        let size: &mut Size2D<f32>;
        unsafe { size = cast::transmute(&scene.size); }
        *size = Size2D(window_width as f32, window_height as f32);
    };

    let composite: fn@() = || {
        #debug("osmain: drawing to screen");

        do util::time::time(~"compositing") {
            adjust_for_window_resizing();
            layers::rendergl::render_scene(context, scene);
        }

        glut::swap_buffers();
        glut::post_redisplay();
    };

    match window {
        GlutWindow(window) => {
            do glut::reshape_func(window) |width, height| {
                #debug("osmain: window resized to %d,%d", width as int, height as int);
                check_for_messages();
                resize_rate_limiter.window_resized(width as uint, height as uint);
                //composite();
            }

            do glut::display_func() {
                debug!("osmain: display func");
                check_for_messages();
                composite();
            }

            while !*done {
                #debug("osmain: running GLUT check loop");
                glut::check_loop();
            }
        }
        ShareWindow(share_context) => {
            loop {
                check_for_messages();
                do util::time::time(~"compositing") {
                    layers::rendergl::render_scene(context, scene);
                }

                share_context.flush();
            }
        }
    }
}

/**
Implementation to allow the osmain channel to be used as a graphics
compositor for the renderer
*/
impl OSMain : Compositor {
    fn begin_drawing(next_dt: pipes::Chan<LayerBufferSet>) {
        self.send(BeginDrawing(move next_dt))
    }
    fn draw(next_dt: pipes::Chan<LayerBufferSet>, draw_me: LayerBufferSet) {
        self.send(Draw(move next_dt, move draw_me))
    }
}

struct SurfaceSet {
    mut front: Surface,
    mut back: Surface,
}

fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<LayerBufferSet>) {
    // We are in a position to lend out the surface?
    assert surfaces.front.have;
    // Ok then take it
    let old_layer_buffers = replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]);
    let new_layer_buffers = do old_layer_buffers.map |layer_buffer| {
        let draw_target_ref = &layer_buffer.draw_target;
        let layer_buffer = LayerBuffer {
            cairo_surface: layer_buffer.cairo_surface.clone(),
            draw_target: draw_target_ref.clone(),
            rect: copy layer_buffer.rect,
            stride: layer_buffer.stride
        };
        #debug("osmain: lending surface %?", layer_buffer);
        move layer_buffer
    };
    surfaces.front.layer_buffer_set.buffers = move old_layer_buffers;

    let new_layer_buffer_set = LayerBufferSet { buffers: move new_layer_buffers };
    receiver.send(move new_layer_buffer_set);
    // Now we don't have it
    surfaces.front.have = false;
    // But we (hopefully) have another!
    surfaces.front <-> surfaces.back;
    // Let's look
    assert surfaces.front.have;
}

fn return_surface(surfaces: &SurfaceSet, layer_buffer_set: LayerBufferSet) {
    #debug("osmain: returning surface %?", layer_buffer_set);
    // We have room for a return
    assert surfaces.front.have;
    assert !surfaces.back.have;

    surfaces.back.layer_buffer_set = move layer_buffer_set;

    // Now we have it again
    surfaces.back.have = true;
}

fn SurfaceSet() -> SurfaceSet {
    SurfaceSet { front: Surface(), back: Surface() }
}

struct Surface {
    layer_buffer_set: LayerBufferSet,
    mut have: bool,
}

fn Surface() -> Surface {
    let cairo_surface = ImageSurface(cairo::CAIRO_FORMAT_RGB24, 800, 600);
    let draw_target = DrawTarget(&cairo_surface);
    let layer_buffer = LayerBuffer {
        cairo_surface: move cairo_surface,
        draw_target: move draw_target,
        rect: Rect(Point2D(0u, 0u), Size2D(800u, 600u)),
        stride: 800
    };
    let layer_buffer_set = LayerBufferSet { buffers: ~[ move layer_buffer ] };
    Surface { layer_buffer_set: move layer_buffer_set, have: true }
}

/// A function for spawning into the platform's main thread
fn on_osmain<T: Send>(f: fn~(po: comm::Port<T>)) -> comm::Chan<T> {
    task::task().sched_mode(task::PlatformThread).spawn_listener(move f)
}

// #[cfg(target_os = "linux")]
mod platform {
    pub fn runmain(f: fn()) {
        f()
    }
}

<commit_msg>platform: Create an image layer for each buffer<commit_after>use ShareGlContext = sharegl::platform::Context;
use azure::azure_hl;
use azure::azure_hl::DrawTarget;
use cairo::cairo_hl::ImageSurface;
use cairo::cairo_surface_t;
use core::util::replace;
use dom::event::{Event, ResizeEvent};
use dvec::DVec;
use geom::matrix::{Matrix4, identity};
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::compositor::{Compositor, LayerBuffer, LayerBufferSet};
use layers::ImageLayer;
use pipes::Chan;
use resize_rate_limiter::ResizeRateLimiter;
use std::cell::Cell;
use std::cmp::FuzzyEq;
use task::TaskBuilder;
use vec::push;

pub type OSMain = comm::Chan<Msg>;

// FIXME: Move me over to opts.rs.
enum Mode {
	GlutMode,
	ShareMode
}

enum Window {
	GlutWindow(glut::Window),
	ShareWindow(ShareGlContext)
}

pub enum Msg {
    BeginDrawing(pipes::Chan<LayerBufferSet>),
    Draw(pipes::Chan<LayerBufferSet>, LayerBufferSet),
    AddKeyHandler(pipes::Chan<()>),
    Exit
}

fn OSMain(dom_event_chan: pipes::SharedChan<Event>) -> OSMain {
    let dom_event_chan = Cell(move dom_event_chan);
    do on_osmain::<Msg> |po, move dom_event_chan| {
        do platform::runmain {
            #debug("preparing to enter main loop");

            // FIXME: Use the servo options.
			let mode;
			match os::getenv("SERVO_SHARE") {
				Some(_) => mode = ShareMode,
				None => mode = GlutMode
			}

	        mainloop(mode, po, dom_event_chan.take());
        }
    }
}

/// Cairo surface wrapping to work with layers
struct CairoSurfaceImageData {
    cairo_surface: ImageSurface,
    size: Size2D<uint>
}

impl CairoSurfaceImageData : layers::layers::ImageData {
    fn size() -> Size2D<uint> { self.size }
    fn stride() -> uint { self.cairo_surface.width() as uint }
    fn format() -> layers::layers::Format { layers::layers::ARGB32Format }
    fn with_data(f: layers::layers::WithDataFn) { f(self.cairo_surface.data()) }
}

fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<Event>) {

    let key_handlers: @DVec<pipes::Chan<()>> = @DVec();

	let window;
	match mode {
		GlutMode => {
			glut::init();
			glut::init_display_mode(glut::DOUBLE);
			let glut_window = glut::create_window(~"Servo");
			glut::reshape_window(glut_window, 800, 600);
			window = GlutWindow(move glut_window);
		}
		ShareMode => {
			let share_context: ShareGlContext = sharegl::base::new(Size2D(800, 600));
			io::println(fmt!("Sharing ID is %d", share_context.id()));
			window = ShareWindow(move share_context);
		}
	}

    let surfaces = @SurfaceSet();

    let context = layers::rendergl::init_render_context();

    let image_data = @layers::layers::BasicImageData::new(
        Size2D(0u, 0u), 0, layers::layers::RGB24Format, ~[]);
    let image = @layers::layers::Image::new(image_data as @layers::layers::ImageData);
    let layers = @dvec::DVec();
    let image_layer = @layers::layers::ImageLayer(image);
    let original_layer_transform = image_layer.common.transform;
    image_layer.common.set_transform(original_layer_transform.scale(&800.0f32, &600.0f32, &1f32));
    layers.push(image_layer);

    let scene = @layers::scene::Scene(layers::layers::ImageLayerKind(image_layer),
                                      Size2D(800.0f32, 600.0f32),
                                      identity(0.0f32));

    let done = @mut false;
    let resize_rate_limiter = @ResizeRateLimiter(move dom_event_chan);
    let check_for_messages = fn@() {

        // Periodically check if content responded to our last resize event
        resize_rate_limiter.check_resize_response();

        // Handle messages
        #debug("osmain: peeking");
        while po.peek() {
            match po.recv() {
                AddKeyHandler(move key_ch) => key_handlers.push(move key_ch),
                BeginDrawing(move sender) => lend_surface(surfaces, move sender),
                Draw(move sender, move dt) => {
                    #debug("osmain: received new frame");
                    return_surface(surfaces, move dt);
                    lend_surface(surfaces, move sender);

                    // Replace the image layer data with the buffer data.
                    let buffers = replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]);
                    for buffers.eachi |i, buffer| {
                        let width = buffer.rect.size.width as uint;
                        let height = buffer.rect.size.height as uint;

                        let image_data = @CairoSurfaceImageData {
                            cairo_surface: buffers[0].cairo_surface.clone(),
                            size: Size2D(width, height)
                        };
                        let image = @layers::layers::Image::new(
                            image_data as @layers::layers::ImageData);

                        // Find or create an image layer.
                        let image_layer;
                        if i < layers.len() {
                            image_layer = layers[i];
                            image_layer.set_image(image);
                        } else {
                            image_layer = @layers::layers::ImageLayer(image);
                        }

                        // Set the layer's transform.
                        let x = buffer.rect.origin.x as f32;
                        let y = buffer.rect.origin.y as f32;
                        image_layer.common.set_transform(
                            original_layer_transform.translate(&x, &y, &0.0f32)
                                .scale(&(width as f32), &(height as f32), &1.0f32));
                    }
                    surfaces.front.layer_buffer_set.buffers = move buffers;
                }
                Exit => {
                    *done = true;
                }
            }
        }
    };

    let adjust_for_window_resizing: fn@() = || {
        let window_width = glut::get(glut::WindowWidth) as uint;
        let window_height = glut::get(glut::WindowHeight) as uint;

        // FIXME: Cross-crate struct mutability is broken.
        let size: &mut Size2D<f32>;
        unsafe { size = cast::transmute(&scene.size); }
        *size = Size2D(window_width as f32, window_height as f32);
    };

    let composite: fn@() = || {
        #debug("osmain: drawing to screen");

        do util::time::time(~"compositing") {
            adjust_for_window_resizing();
            layers::rendergl::render_scene(context, scene);
        }

        glut::swap_buffers();
        glut::post_redisplay();
    };

    match window {
        GlutWindow(window) => {
            do glut::reshape_func(window) |width, height| {
                #debug("osmain: window resized to %d,%d", width as int, height as int);
                check_for_messages();
                resize_rate_limiter.window_resized(width as uint, height as uint);
                //composite();
            }

            do glut::display_func() {
                debug!("osmain: display func");
                check_for_messages();
                composite();
            }

            while !*done {
                #debug("osmain: running GLUT check loop");
                glut::check_loop();
            }
        }
        ShareWindow(share_context) => {
            loop {
                check_for_messages();
                do util::time::time(~"compositing") {
                    layers::rendergl::render_scene(context, scene);
                }

                share_context.flush();
            }
        }
    }
}

/**
Implementation to allow the osmain channel to be used as a graphics
compositor for the renderer
*/
impl OSMain : Compositor {
    fn begin_drawing(next_dt: pipes::Chan<LayerBufferSet>) {
        self.send(BeginDrawing(move next_dt))
    }
    fn draw(next_dt: pipes::Chan<LayerBufferSet>, draw_me: LayerBufferSet) {
        self.send(Draw(move next_dt, move draw_me))
    }
}

struct SurfaceSet {
    mut front: Surface,
    mut back: Surface,
}

fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<LayerBufferSet>) {
    // We are in a position to lend out the surface?
    assert surfaces.front.have;
    // Ok then take it
    let old_layer_buffers = replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]);
    let new_layer_buffers = do old_layer_buffers.map |layer_buffer| {
        let draw_target_ref = &layer_buffer.draw_target;
        let layer_buffer = LayerBuffer {
            cairo_surface: layer_buffer.cairo_surface.clone(),
            draw_target: draw_target_ref.clone(),
            rect: copy layer_buffer.rect,
            stride: layer_buffer.stride
        };
        #debug("osmain: lending surface %?", layer_buffer);
        move layer_buffer
    };
    surfaces.front.layer_buffer_set.buffers = move old_layer_buffers;

    let new_layer_buffer_set = LayerBufferSet { buffers: move new_layer_buffers };
    receiver.send(move new_layer_buffer_set);
    // Now we don't have it
    surfaces.front.have = false;
    // But we (hopefully) have another!
    surfaces.front <-> surfaces.back;
    // Let's look
    assert surfaces.front.have;
}

fn return_surface(surfaces: &SurfaceSet, layer_buffer_set: LayerBufferSet) {
    #debug("osmain: returning surface %?", layer_buffer_set);
    // We have room for a return
    assert surfaces.front.have;
    assert !surfaces.back.have;

    surfaces.back.layer_buffer_set = move layer_buffer_set;

    // Now we have it again
    surfaces.back.have = true;
}

fn SurfaceSet() -> SurfaceSet {
    SurfaceSet { front: Surface(), back: Surface() }
}

struct Surface {
    layer_buffer_set: LayerBufferSet,
    mut have: bool,
}

fn Surface() -> Surface {
    let cairo_surface = ImageSurface(cairo::CAIRO_FORMAT_RGB24, 800, 600);
    let draw_target = DrawTarget(&cairo_surface);
    let layer_buffer = LayerBuffer {
        cairo_surface: move cairo_surface,
        draw_target: move draw_target,
        rect: Rect(Point2D(0u, 0u), Size2D(800u, 600u)),
        stride: 800
    };
    let layer_buffer_set = LayerBufferSet { buffers: ~[ move layer_buffer ] };
    Surface { layer_buffer_set: move layer_buffer_set, have: true }
}

/// A function for spawning into the platform's main thread
fn on_osmain<T: Send>(f: fn~(po: comm::Port<T>)) -> comm::Chan<T> {
    task::task().sched_mode(task::PlatformThread).spawn_listener(move f)
}

// #[cfg(target_os = "linux")]
mod platform {
    pub fn runmain(f: fn()) {
        f()
    }
}

<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use num_traits::{
    cast::{AsPrimitive, ToPrimitive},
    identities::{One, Zero},
    int::PrimInt,
    ops::wrapping::{WrappingMul, WrappingNeg, WrappingSub},
};
use std::fmt::{Debug, Display};
use std::mem::swap;

// This is incorrectly reported as dead code,
//  presumably when included in build.rs.
#[allow(dead_code)]
pub(crate) fn gcd(mut a: u64, mut b: u64) -> u64 {
    while b > 0 {
        a %= b;
        swap(&mut a, &mut b);
    }
    a
}

pub(crate) trait Arithmetic: Copy + Sized {
    type I: Copy + Sized + Eq;

    fn new(m: u64) -> Self;
    fn modulus(&self) -> u64;
    fn from_u64(&self, n: u64) -> Self::I;
    fn to_u64(&self, n: Self::I) -> u64;
    fn add(&self, a: Self::I, b: Self::I) -> Self::I;
    fn mul(&self, a: Self::I, b: Self::I) -> Self::I;

    fn pow(&self, mut a: Self::I, mut b: u64) -> Self::I {
        let (_a, _b) = (a, b);
        let mut result = self.one();
        while b > 0 {
            if b & 1 != 0 {
                result = self.mul(result, a);
            }
            a = self.mul(a, a);
            b >>= 1;
        }

        // Check that r (reduced back to the usual representation) equals
        //  a^b % n, unless the latter computation overflows
        // Temporarily commented-out, as there u64::checked_pow is not available
        //  on the minimum supported Rust version, nor is an appropriate method
        //  for compiling the check conditionally.
        //debug_assert!(self
        //    .to_u64(_a)
        //    .checked_pow(_b as u32)
        //    .map(|r| r % self.modulus() == self.to_u64(result))
        //    .unwrap_or(true));

        result
    }

    fn one(&self) -> Self::I {
        self.from_u64(1)
    }
    fn minus_one(&self) -> Self::I {
        self.from_u64(self.modulus() - 1)
    }
    fn zero(&self) -> Self::I {
        self.from_u64(0)
    }
}

#[derive(Clone, Copy, Debug)]
pub(crate) struct Montgomery<T: DoubleInt> {
    a: T,
    n: T,
}

impl<T: DoubleInt> Montgomery<T> {
    /// computes x/R mod n efficiently
    fn reduce(&self, x: T::Double) -> T {
        let t_bits = T::zero().count_zeros() as usize;

        debug_assert!(x < (self.n.as_double()) << t_bits);
        // TODO: optimiiiiiiise
        let Montgomery { a, n } = self;
        let m = T::from_double(x).wrapping_mul(a);
        let nm = (n.as_double()) * (m.as_double());
        let (xnm, overflow) = x.overflowing_add_(nm); // x + n*m
        debug_assert_eq!(
            xnm % (T::Double::one() << T::zero().count_zeros() as usize),
            T::Double::zero()
        );

        // (x + n*m) / R
        // in case of overflow, this is (2¹²⁸ + xnm)/2⁶⁴ - n = xnm/2⁶⁴ + (2⁶⁴ - n)
        let y = T::from_double(xnm >> t_bits)
            + if !overflow {
                T::zero()
            } else {
                n.wrapping_neg()
            };

        if y >= *n {
            y - *n
        } else {
            y
        }
    }
}

impl<T: DoubleInt> Arithmetic for Montgomery<T> {
    // Montgomery transform, R=2⁶⁴
    // Provides fast arithmetic mod n (n odd, u64)
    type I = T;

    fn new(n: u64) -> Self {
        debug_assert!(T::zero().count_zeros() >= 64 || n < (1 << T::zero().count_zeros() as usize));
        let n = T::from_u64(n);
        let a = modular_inverse(n).wrapping_neg();
        debug_assert_eq!(n.wrapping_mul(&a), T::one().wrapping_neg());
        Montgomery { a, n }
    }

    fn modulus(&self) -> u64 {
        self.n.as_()
    }

    fn from_u64(&self, x: u64) -> Self::I {
        // TODO: optimise!
        debug_assert!(x < self.n.as_());
        let r = T::from_double(
            ((T::Double::from(x)) << T::zero().count_zeros() as usize) % self.n.as_double(),
        );
        debug_assert_eq!(x, self.to_u64(r));
        r
    }

    fn to_u64(&self, n: Self::I) -> u64 {
        self.reduce(n.as_double()).as_()
    }

    fn add(&self, a: Self::I, b: Self::I) -> Self::I {
        let (r, overflow) = a.overflowing_add_(b);

        // In case of overflow, a+b = 2⁶⁴ + r = (2⁶⁴ - n) + r (working mod n)
        let r = if !overflow {
            r
        } else {
            r + self.n.wrapping_neg()
        };

        // Normalise to [0; n[
        let r = if r < self.n { r } else { r - self.n };

        // Check that r (reduced back to the usual representation) equals
        // a+b % n
        #[cfg(debug_assertions)]
        {
            let a_r = self.to_u64(a);
            let b_r = self.to_u64(b);
            let r_r = self.to_u64(r);
            let r_2 =
                (((a_r as u128) + (b_r as u128)) % <T as AsPrimitive<u128>>::as_(self.n)) as u64;
            debug_assert_eq!(
                r_r, r_2,
                "[{}] = {} ≠ {} = {} + {} = [{}] + [{}] mod {}; a = {}",
                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
            );
        }
        r
    }

    fn mul(&self, a: Self::I, b: Self::I) -> Self::I {
        let r = self.reduce(a.as_double() * b.as_double());

        // Check that r (reduced back to the usual representation) equals
        // a*b % n
        #[cfg(debug_assertions)]
        {
            let a_r = self.to_u64(a);
            let b_r = self.to_u64(b);
            let r_r = self.to_u64(r);
            let r_2: u64 = ((T::Double::from(a_r) * T::Double::from(b_r)) % self.n.as_double())
                .to_u64()
                .unwrap();
            debug_assert_eq!(
                r_r, r_2,
                "[{}] = {} ≠ {} = {} * {} = [{}] * [{}] mod {}; a = {}",
                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
            );
        }
        r
    }
}

// NOTE: Trait can be removed once num-traits adds a similar one;
//       see https://github.com/rust-num/num-traits/issues/168
pub(crate) trait OverflowingAdd: Sized {
    fn overflowing_add_(self, n: Self) -> (Self, bool);
}
impl OverflowingAdd for u32 {
    fn overflowing_add_(self, n: Self) -> (Self, bool) {
        self.overflowing_add(n)
    }
}
impl OverflowingAdd for u64 {
    fn overflowing_add_(self, n: Self) -> (Self, bool) {
        self.overflowing_add(n)
    }
}
impl OverflowingAdd for u128 {
    fn overflowing_add_(self, n: Self) -> (Self, bool) {
        self.overflowing_add(n)
    }
}

pub(crate) trait Int:
    AsPrimitive<u64>
    + AsPrimitive<u128>
    + Display
    + Debug
    + PrimInt
    + OverflowingAdd
    + WrappingNeg
    + WrappingSub
    + WrappingMul
{
}

pub(crate) trait DoubleInt: Int {
    type Double: Int + From<u64> + ToPrimitive;

    fn as_double(self) -> Self::Double;
    fn from_double(n: Self::Double) -> Self;
    fn from_u64(n: u64) -> Self;
}

impl Int for u32 {}
impl Int for u64 {}
impl Int for u128 {}

impl DoubleInt for u64 {
    type Double = u128;

    fn as_double(self) -> u128 {
        self as _
    }
    fn from_double(n: u128) -> u64 {
        n as _
    }
    fn from_u64(n: u64) -> u64 {
        n
    }
}
impl DoubleInt for u32 {
    type Double = u64;

    fn as_double(self) -> u64 {
        self as _
    }
    fn from_double(n: u64) -> u32 {
        n as _
    }
    fn from_u64(n: u64) -> u32 {
        n as _
    }
}

// extended Euclid algorithm
// precondition: a is odd
pub(crate) fn modular_inverse<T: Int>(a: T) -> T {
    let zero = T::zero();
    let one = T::one();
    debug_assert!(a % (one + one) == one, "{:?} is not odd", a);

    let mut t = zero;
    let mut newt = one;
    let mut r = zero;
    let mut newr = a;

    while newr != zero {
        let quot = if r == zero {
            // special case when we're just starting out
            // This works because we know that
            // a does not divide 2^64, so floor(2^64 / a) == floor((2^64-1) / a);
            T::max_value()
        } else {
            r
        } / newr;

        let newtp = t.wrapping_sub(&quot.wrapping_mul(&newt));
        t = newt;
        newt = newtp;

        let newrp = r.wrapping_sub(&quot.wrapping_mul(&newr));
        r = newr;
        newr = newrp;
    }

    debug_assert_eq!(r, one);
    t
}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_inverter<T: Int>() {
        // All odd integers from 1 to 20 000
        let one = T::from(1).unwrap();
        let two = T::from(2).unwrap();
        let mut test_values = (0..10_000)
            .map(|i| T::from(i).unwrap())
            .map(|i| two * i + one);

        assert!(test_values.all(|x| x.wrapping_mul(&modular_inverse(x)) == one));
    }

    #[test]
    fn test_inverter_u32() {
        test_inverter::<u32>()
    }

    #[test]
    fn test_inverter_u64() {
        test_inverter::<u64>()
    }

    fn test_add<A: Arithmetic>() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = A::new(n);
            for x in 0..n {
                let m_x = m.from_u64(x);
                for y in 0..=x {
                    let m_y = m.from_u64(y);
                    println!("{n:?}, {x:?}, {y:?}", n = n, x = x, y = y);
                    assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y)));
                }
            }
        }
    }

    #[test]
    fn test_add_m32() {
        test_add::<Montgomery<u32>>()
    }

    #[test]
    fn test_add_m64() {
        test_add::<Montgomery<u64>>()
    }

    fn test_mult<A: Arithmetic>() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = A::new(n);
            for x in 0..n {
                let m_x = m.from_u64(x);
                for y in 0..=x {
                    let m_y = m.from_u64(y);
                    assert_eq!((x * y) % n, m.to_u64(m.mul(m_x, m_y)));
                }
            }
        }
    }

    #[test]
    fn test_mult_m32() {
        test_mult::<Montgomery<u32>>()
    }

    #[test]
    fn test_mult_m64() {
        test_mult::<Montgomery<u64>>()
    }

    fn test_roundtrip<A: Arithmetic>() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = A::new(n);
            for x in 0..n {
                let x_ = m.from_u64(x);
                assert_eq!(x, m.to_u64(x_));
            }
        }
    }

    #[test]
    fn test_roundtrip_m32() {
        test_roundtrip::<Montgomery<u32>>()
    }

    #[test]
    fn test_roundtrip_m64() {
        test_roundtrip::<Montgomery<u64>>()
    }
}
<commit_msg>factor::numeric::Arithmetic: Rename associated type I to ModInt<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
// * (c) 2020 nicoo            <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

use num_traits::{
    cast::{AsPrimitive, ToPrimitive},
    identities::{One, Zero},
    int::PrimInt,
    ops::wrapping::{WrappingMul, WrappingNeg, WrappingSub},
};
use std::fmt::{Debug, Display};
use std::mem::swap;

// This is incorrectly reported as dead code,
//  presumably when included in build.rs.
#[allow(dead_code)]
pub(crate) fn gcd(mut a: u64, mut b: u64) -> u64 {
    while b > 0 {
        a %= b;
        swap(&mut a, &mut b);
    }
    a
}

pub(crate) trait Arithmetic: Copy + Sized {
    // The type of integers mod m, in some opaque representation
    type ModInt: Copy + Sized + Eq;

    fn new(m: u64) -> Self;
    fn modulus(&self) -> u64;
    fn from_u64(&self, n: u64) -> Self::ModInt;
    fn to_u64(&self, n: Self::ModInt) -> u64;
    fn add(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt;
    fn mul(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt;

    fn pow(&self, mut a: Self::ModInt, mut b: u64) -> Self::ModInt {
        let (_a, _b) = (a, b);
        let mut result = self.one();
        while b > 0 {
            if b & 1 != 0 {
                result = self.mul(result, a);
            }
            a = self.mul(a, a);
            b >>= 1;
        }

        // Check that r (reduced back to the usual representation) equals
        //  a^b % n, unless the latter computation overflows
        // Temporarily commented-out, as there u64::checked_pow is not available
        //  on the minimum supported Rust version, nor is an appropriate method
        //  for compiling the check conditionally.
        //debug_assert!(self
        //    .to_u64(_a)
        //    .checked_pow(_b as u32)
        //    .map(|r| r % self.modulus() == self.to_u64(result))
        //    .unwrap_or(true));

        result
    }

    fn one(&self) -> Self::ModInt {
        self.from_u64(1)
    }
    fn minus_one(&self) -> Self::ModInt {
        self.from_u64(self.modulus() - 1)
    }
    fn zero(&self) -> Self::ModInt {
        self.from_u64(0)
    }
}

#[derive(Clone, Copy, Debug)]
pub(crate) struct Montgomery<T: DoubleInt> {
    a: T,
    n: T,
}

impl<T: DoubleInt> Montgomery<T> {
    /// computes x/R mod n efficiently
    fn reduce(&self, x: T::Double) -> T {
        let t_bits = T::zero().count_zeros() as usize;

        debug_assert!(x < (self.n.as_double()) << t_bits);
        // TODO: optimiiiiiiise
        let Montgomery { a, n } = self;
        let m = T::from_double(x).wrapping_mul(a);
        let nm = (n.as_double()) * (m.as_double());
        let (xnm, overflow) = x.overflowing_add_(nm); // x + n*m
        debug_assert_eq!(
            xnm % (T::Double::one() << T::zero().count_zeros() as usize),
            T::Double::zero()
        );

        // (x + n*m) / R
        // in case of overflow, this is (2¹²⁸ + xnm)/2⁶⁴ - n = xnm/2⁶⁴ + (2⁶⁴ - n)
        let y = T::from_double(xnm >> t_bits)
            + if !overflow {
                T::zero()
            } else {
                n.wrapping_neg()
            };

        if y >= *n {
            y - *n
        } else {
            y
        }
    }
}

impl<T: DoubleInt> Arithmetic for Montgomery<T> {
    // Montgomery transform, R=2⁶⁴
    // Provides fast arithmetic mod n (n odd, u64)
    type ModInt = T;

    fn new(n: u64) -> Self {
        debug_assert!(T::zero().count_zeros() >= 64 || n < (1 << T::zero().count_zeros() as usize));
        let n = T::from_u64(n);
        let a = modular_inverse(n).wrapping_neg();
        debug_assert_eq!(n.wrapping_mul(&a), T::one().wrapping_neg());
        Montgomery { a, n }
    }

    fn modulus(&self) -> u64 {
        self.n.as_()
    }

    fn from_u64(&self, x: u64) -> Self::ModInt {
        // TODO: optimise!
        debug_assert!(x < self.n.as_());
        let r = T::from_double(
            ((T::Double::from(x)) << T::zero().count_zeros() as usize) % self.n.as_double(),
        );
        debug_assert_eq!(x, self.to_u64(r));
        r
    }

    fn to_u64(&self, n: Self::ModInt) -> u64 {
        self.reduce(n.as_double()).as_()
    }

    fn add(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt {
        let (r, overflow) = a.overflowing_add_(b);

        // In case of overflow, a+b = 2⁶⁴ + r = (2⁶⁴ - n) + r (working mod n)
        let r = if !overflow {
            r
        } else {
            r + self.n.wrapping_neg()
        };

        // Normalise to [0; n[
        let r = if r < self.n { r } else { r - self.n };

        // Check that r (reduced back to the usual representation) equals
        // a+b % n
        #[cfg(debug_assertions)]
        {
            let a_r = self.to_u64(a);
            let b_r = self.to_u64(b);
            let r_r = self.to_u64(r);
            let r_2 =
                (((a_r as u128) + (b_r as u128)) % <T as AsPrimitive<u128>>::as_(self.n)) as u64;
            debug_assert_eq!(
                r_r, r_2,
                "[{}] = {} ≠ {} = {} + {} = [{}] + [{}] mod {}; a = {}",
                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
            );
        }
        r
    }

    fn mul(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt {
        let r = self.reduce(a.as_double() * b.as_double());

        // Check that r (reduced back to the usual representation) equals
        // a*b % n
        #[cfg(debug_assertions)]
        {
            let a_r = self.to_u64(a);
            let b_r = self.to_u64(b);
            let r_r = self.to_u64(r);
            let r_2: u64 = ((T::Double::from(a_r) * T::Double::from(b_r)) % self.n.as_double())
                .to_u64()
                .unwrap();
            debug_assert_eq!(
                r_r, r_2,
                "[{}] = {} ≠ {} = {} * {} = [{}] * [{}] mod {}; a = {}",
                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
            );
        }
        r
    }
}

// NOTE: Trait can be removed once num-traits adds a similar one;
//       see https://github.com/rust-num/num-traits/issues/168
pub(crate) trait OverflowingAdd: Sized {
    fn overflowing_add_(self, n: Self) -> (Self, bool);
}
impl OverflowingAdd for u32 {
    fn overflowing_add_(self, n: Self) -> (Self, bool) {
        self.overflowing_add(n)
    }
}
impl OverflowingAdd for u64 {
    fn overflowing_add_(self, n: Self) -> (Self, bool) {
        self.overflowing_add(n)
    }
}
impl OverflowingAdd for u128 {
    fn overflowing_add_(self, n: Self) -> (Self, bool) {
        self.overflowing_add(n)
    }
}

pub(crate) trait Int:
    AsPrimitive<u64>
    + AsPrimitive<u128>
    + Display
    + Debug
    + PrimInt
    + OverflowingAdd
    + WrappingNeg
    + WrappingSub
    + WrappingMul
{
}

pub(crate) trait DoubleInt: Int {
    type Double: Int + From<u64> + ToPrimitive;

    fn as_double(self) -> Self::Double;
    fn from_double(n: Self::Double) -> Self;
    fn from_u64(n: u64) -> Self;
}

impl Int for u32 {}
impl Int for u64 {}
impl Int for u128 {}

impl DoubleInt for u64 {
    type Double = u128;

    fn as_double(self) -> u128 {
        self as _
    }
    fn from_double(n: u128) -> u64 {
        n as _
    }
    fn from_u64(n: u64) -> u64 {
        n
    }
}
impl DoubleInt for u32 {
    type Double = u64;

    fn as_double(self) -> u64 {
        self as _
    }
    fn from_double(n: u64) -> u32 {
        n as _
    }
    fn from_u64(n: u64) -> u32 {
        n as _
    }
}

// extended Euclid algorithm
// precondition: a is odd
pub(crate) fn modular_inverse<T: Int>(a: T) -> T {
    let zero = T::zero();
    let one = T::one();
    debug_assert!(a % (one + one) == one, "{:?} is not odd", a);

    let mut t = zero;
    let mut newt = one;
    let mut r = zero;
    let mut newr = a;

    while newr != zero {
        let quot = if r == zero {
            // special case when we're just starting out
            // This works because we know that
            // a does not divide 2^64, so floor(2^64 / a) == floor((2^64-1) / a);
            T::max_value()
        } else {
            r
        } / newr;

        let newtp = t.wrapping_sub(&quot.wrapping_mul(&newt));
        t = newt;
        newt = newtp;

        let newrp = r.wrapping_sub(&quot.wrapping_mul(&newr));
        r = newr;
        newr = newrp;
    }

    debug_assert_eq!(r, one);
    t
}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_inverter<T: Int>() {
        // All odd integers from 1 to 20 000
        let one = T::from(1).unwrap();
        let two = T::from(2).unwrap();
        let mut test_values = (0..10_000)
            .map(|i| T::from(i).unwrap())
            .map(|i| two * i + one);

        assert!(test_values.all(|x| x.wrapping_mul(&modular_inverse(x)) == one));
    }

    #[test]
    fn test_inverter_u32() {
        test_inverter::<u32>()
    }

    #[test]
    fn test_inverter_u64() {
        test_inverter::<u64>()
    }

    fn test_add<A: Arithmetic>() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = A::new(n);
            for x in 0..n {
                let m_x = m.from_u64(x);
                for y in 0..=x {
                    let m_y = m.from_u64(y);
                    println!("{n:?}, {x:?}, {y:?}", n = n, x = x, y = y);
                    assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y)));
                }
            }
        }
    }

    #[test]
    fn test_add_m32() {
        test_add::<Montgomery<u32>>()
    }

    #[test]
    fn test_add_m64() {
        test_add::<Montgomery<u64>>()
    }

    fn test_mult<A: Arithmetic>() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = A::new(n);
            for x in 0..n {
                let m_x = m.from_u64(x);
                for y in 0..=x {
                    let m_y = m.from_u64(y);
                    assert_eq!((x * y) % n, m.to_u64(m.mul(m_x, m_y)));
                }
            }
        }
    }

    #[test]
    fn test_mult_m32() {
        test_mult::<Montgomery<u32>>()
    }

    #[test]
    fn test_mult_m64() {
        test_mult::<Montgomery<u64>>()
    }

    fn test_roundtrip<A: Arithmetic>() {
        for n in 0..100 {
            let n = 2 * n + 1;
            let m = A::new(n);
            for x in 0..n {
                let x_ = m.from_u64(x);
                assert_eq!(x, m.to_u64(x_));
            }
        }
    }

    #[test]
    fn test_roundtrip_m32() {
        test_roundtrip::<Montgomery<u32>>()
    }

    #[test]
    fn test_roundtrip_m64() {
        test_roundtrip::<Montgomery<u64>>()
    }
}
<|endoftext|>


<commit_before>use nalgebra::{Vector3, Repeat, Point3, FloatPoint, BaseFloat, ApproxEq};
use num::Zero;

/// Represents result of a steering behaviour computation. User can aggregate
/// more than one behaviour result into single acceleration struct.
pub struct SteeringAcceleration<T: BaseFloat + ApproxEq<T>> {
    /// linear acceleration component
    pub linear: Vector3<T>,
    /// angular acceleration component
    pub angular: T,
}

impl<T: BaseFloat + ApproxEq<T>> SteeringAcceleration<T> {
    /// Creates a steering acceleration struct using given linear and angular components
    fn new(linear_acceleration: Vector3<T>, angular_acceleration: T) -> SteeringAcceleration<T> {
        SteeringAcceleration {
            linear: linear_acceleration,
            angular: angular_acceleration,
        }
    }

    /// Tests whether both linear and angular acceleration compenents are zero
    fn is_zero(self: &Self) -> bool {
        self.angular.is_zero() && self.linear.is_zero()
    }

    /// Sets both compononents to zero
    fn set_zero(self: &mut Self) -> &mut Self {
        self.angular = T::zero();
        self.linear = Vector3::zero();
        self
    }

    ///
    fn add(self: &mut Self, other: SteeringAcceleration<T>) -> &mut Self {
        self.angular = self.angular + other.angular;
        self.linear += other.linear;
        self
    }

    ///
    fn scl(self: &mut Self, scale: T) -> &mut Self {
        self.angular = self.angular * scale;
        self.linear *= Vector3::repeat(scale);
        self
    }

    ///
    fn mulAdd(self: &mut Self, other: SteeringAcceleration<T>, scale: T) -> &mut Self {
        self.angular = self.angular + (other.angular * scale);
        self.linear += other.linear * Vector3::repeat(scale);
        self
    }

    ///
    fn calculate_square_magnitude(self: &Self) -> T {
        self.linear.as_point().distance_squared(&Vector3::zero().to_point()) +
        self.angular * self.angular
    }

    ///
    fn calculate_magnitude(self: &Self) -> T {
        self.calculate_square_magnitude().sqrt()
    }
}

pub trait SteeringAccelerationCalculator<T: BaseFloat + ApproxEq<T>> {
    fn calculate_steering<'a>(self: &mut Self,
                              steering_acceleration: &'a mut SteeringAcceleration<T>)
                              -> &'a mut SteeringAcceleration<T> {
        if self.is_enabled() {
            self.calculate_real_steering(steering_acceleration)
        } else {
            steering_acceleration.set_zero()
        }
    }
    fn calculate_real_steering<'a>(self: &mut Self,
                                   steering_acceleration: &'a mut SteeringAcceleration<T>)
                                   -> &'a mut SteeringAcceleration<T>;
    fn is_enabled(self: &Self) -> bool;
}

#[cfg(test)]
mod test {
    use super::SteeringAcceleration;
    use nalgebra::Vector3;
    #[test]
    fn is_zero_positive() {
        let mut acceleration = SteeringAcceleration::new(Vector3::new(1.0f32, 2.0, 3.0), 5.0f32);
        acceleration.set_zero();
        assert!(acceleration.is_zero());
    }

    #[test]
    fn is_zero_negative(){
        let mut acceleration = SteeringAcceleration::new(Vector3::new(1.0f32, 2.0, 3.0), 5.0f32);
        assert_eq!(acceleration.is_zero(), false);
    }
}
<commit_msg>more tests added<commit_after>use nalgebra::{Vector3, Repeat, Point3, FloatPoint, BaseFloat, ApproxEq};
use num::Zero;

/// Represents result of a steering behaviour computation. User can aggregate
/// more than one behaviour result into single acceleration struct.
#[derive(Debug)]
pub struct SteeringAcceleration<T: BaseFloat + ApproxEq<T>> {
    /// linear acceleration component
    pub linear: Vector3<T>,
    /// angular acceleration component
    pub angular: T,
}

impl<T: BaseFloat + ApproxEq<T>> SteeringAcceleration<T> {
    /// Creates a steering acceleration struct using given linear and angular components
    fn new(linear_acceleration: Vector3<T>, angular_acceleration: T) -> SteeringAcceleration<T> {
        SteeringAcceleration {
            linear: linear_acceleration,
            angular: angular_acceleration,
        }
    }

    /// Tests whether both linear and angular acceleration compenents are zero
    fn is_zero(self: &Self) -> bool {
        self.angular.is_zero() && self.linear.is_zero()
    }

    /// Sets both compononents to zero
    fn set_zero(self: &mut Self) -> &mut Self {
        self.angular = T::zero();
        self.linear = Vector3::zero();
        self
    }

    ///
    fn add(self: &mut Self, other: SteeringAcceleration<T>) -> &mut Self {
        self.angular = self.angular + other.angular;
        self.linear += other.linear;
        self
    }

    ///
    fn scl(self: &mut Self, scale: T) -> &mut Self {
        self.angular = self.angular * scale;
        self.linear *= Vector3::repeat(scale);
        self
    }

    ///
    fn mulAdd(self: &mut Self, other: SteeringAcceleration<T>, scale: T) -> &mut Self {
        self.angular = self.angular + (other.angular * scale);
        self.linear += other.linear * Vector3::repeat(scale);
        self
    }

    ///
    fn calculate_square_magnitude(self: &Self) -> T {
        self.linear.as_point().distance_squared(&Vector3::zero().to_point()) +
        self.angular * self.angular
    }

    ///
    fn calculate_magnitude(self: &Self) -> T {
        self.calculate_square_magnitude().sqrt()
    }
}

impl<T: BaseFloat + ApproxEq<T>> PartialEq for SteeringAcceleration<T> {
    fn eq(&self, other: &Self) -> bool {
        self.linear == other.linear && self.angular == other.angular
    }
    fn ne(&self, other: &Self) -> bool {
        self.linear != other.linear || self.angular != other.angular
    }
}

pub trait SteeringAccelerationCalculator<T: BaseFloat + ApproxEq<T>> {
    fn calculate_steering<'a>(self: &mut Self,
                              steering_acceleration: &'a mut SteeringAcceleration<T>)
                              -> &'a mut SteeringAcceleration<T> {
        if self.is_enabled() {
            self.calculate_real_steering(steering_acceleration)
        } else {
            steering_acceleration.set_zero()
        }
    }
    fn calculate_real_steering<'a>(self: &mut Self,
                                   steering_acceleration: &'a mut SteeringAcceleration<T>)
                                   -> &'a mut SteeringAcceleration<T>;
    fn is_enabled(self: &Self) -> bool;
}

#[cfg(test)]
mod test {
    use super::SteeringAcceleration;
    use nalgebra::Vector3;
    #[test]
    fn is_zero_positive() {
        let mut acceleration = SteeringAcceleration::new(Vector3::new(1.0f32, 2.0, 3.0), 5.0f32);
        acceleration.set_zero();
        assert!(acceleration.is_zero());
    }

    #[test]
    fn is_zero_negative() {
        let mut acceleration = SteeringAcceleration::new(Vector3::new(1.0f32, 2.0, 3.0), 5.0f32);
        assert_eq!(acceleration.is_zero(), false);
    }

    #[test]
    fn add() {
        let mut acceleration = SteeringAcceleration::new(Vector3::new(1.0f32, 1.0, 1.0), 1.0f32);
        let acceleration2 = SteeringAcceleration::new(Vector3::new(1.0f32, 1.0, 1.0), 1.0f32);
        acceleration.add(acceleration2);
        assert_eq!(SteeringAcceleration::new(Vector3::new(2.0f32, 2.0, 2.0), 2.0f32), acceleration);
    }

    #[test]
    fn scl(){
        let mut acceleration = SteeringAcceleration::new(Vector3::new(1.0f32,1.0,1.0), 1.0f32);
        acceleration.scl(2.0f32);
        assert_eq!(SteeringAcceleration::new(Vector3::new(2.0f32, 2.0, 2.0), 2.0), acceleration);
    }

    #[test]
    fn calculate_square_magnitude(){
        let mut acceleration = SteeringAcceleration::new(Vector3::new(2.0f32,2.0,2.0), 2.0f32);
        assert_eq!(16f32, acceleration.calculate_square_magnitude());
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Intterupt handling on x86 machines.
//!
//! This module provides support for interrupt handling on both `x86` and
//! `x86_64` as a black box. Code that depends on this can use the same API
//! regardless of system word size.
use core::fmt::Write;

use arch::cpu::{control_regs, Registers};
use arch::cpu::dtable::DTable;

use io::term::CONSOLE;
use io::keyboard;

use vga::Color;

use spin::Mutex;

pub mod idt;
pub mod pics;

use self::idt::Idt;

/// State stored when handling an interrupt.
#[repr(C, packed)]
pub struct InterruptContext { /// callee-saved registers
                              pub registers: Registers
                            , /// interrupt ID number
                              pub int_id: usize
                            //, _pad_1: u32
                            //, /// error number
                            //  pub err_no:  u32
                            //, _pad_2: u32
                            }

//impl InterruptContext {
//    /// Fetches the corresponding CPU exception for this interrupt, if this
//    /// interrupt is a CPU exception.
//    #[inline]
//
//}

#[derive(Debug)]
pub struct ExceptionInfo { pub name: &'static str
                         , pub mnemonic: &'static str
                         , pub irq_type: &'static str
                         , pub source: &'static str
                         }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: [ExceptionInfo; 20]
    = [ ExceptionInfo { name: "Divide-By-Zero Error"
                      , mnemonic: "#DE", irq_type: "Fault"
                      , source: "DIV or IDIV instruction" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "#DB", irq_type: "Fault/trap"
                      , source: "Reserved for Intel use" }
      , ExceptionInfo { name: "Non-Maskable Interrupt"
                      , mnemonic: "NMI", irq_type: "Interrupt"
                      , source: "Non-maskable external interrupt" }
      , ExceptionInfo { name: "Breakpoint"
                      , mnemonic: "#BP", irq_type: "Trap"
                      , source: "INT 3 instruction" }
      , ExceptionInfo { name: "Overflow"
                      , mnemonic: "#OF", irq_type: "Trap"
                      , source: "INTO instruction" }
      , ExceptionInfo { name: "BOUND Range Exceeded"
                      , mnemonic: "#BR", irq_type: "Fault"
                      , source: "BOUND instruction" }
      , ExceptionInfo { name: "Undefined Opcode"
                     , mnemonic: "#UD", irq_type: "Fault"
                     , source: "UD2 instruction or reserved opcode" }
      , ExceptionInfo { name: "Device Not Available"
                      , mnemonic: "#NM", irq_type: "Fault"
                      , source: "Floating-point or WAIT/FWAIT instruction\
                                 (no math coprocessor)" }
      , ExceptionInfo { name: "Double Fault"
                      , mnemonic: "#DF", irq_type: "Abort"
                      , source: "Any instruction that can generate an\
                                 exception, a NMI, or an INTR" }
      , ExceptionInfo { name: "Coprocessor Segment Overrun"
                      , mnemonic: "", irq_type: "Fault"
                      , source: "Any floating-point instruction" }
      , ExceptionInfo { name: "Invalid TSS"
                      , mnemonic: "#TS", irq_type: "Fault"
                      , source: "Task switch or TSS access" }
      , ExceptionInfo { name: "Segment Not Present"
                      , mnemonic: "#NP", irq_type: "Fault"
                      , source: "Loading segment registers or accessing\
                                 system segments" }
      , ExceptionInfo { name: "Stack-Segment Fault"
                      , mnemonic: "#SS", irq_type: "Fault"
                      , source: "Stack operations and SS register loads" }
      , ExceptionInfo { name: "General Protection"
                      , mnemonic: "#GP", irq_type: "Fault"
                      , source: "Any memory reference or other protection\
                                 checks" }
      , ExceptionInfo { name: "Page Fault"
                      , mnemonic: "#PF", irq_type: "Fault"
                      , source: "Any memory reference" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "", irq_type: ""
                      , source: "RESERVED FOR INTEL USE \n This should never \
                                 happen. Something is very wrong." }
      , ExceptionInfo { name: "x87 FPU Floating-Point Error (Math Fault)"
                      , mnemonic: "#MF", irq_type: "Fault"
                      , source: "x87 FPU floating-point or WAIT/FWAIT\
                                 instruction" }
      , ExceptionInfo { name: "Alignment Check"
                      , mnemonic: "#AC", irq_type: "Fault"
                      , source: "Any data reference in memory" }
      , ExceptionInfo { name: "Machine Check"
                      , mnemonic: "#MC", irq_type: "Abort"
                      , source: "Model-dependent" }
      , ExceptionInfo { name: "SIMD Floating-Point Exception"
                      , mnemonic: "#XM", irq_type: "Fault"
                      , source: "SSE/SSE2/SSE3 floating-point instructions" }
       ];

//==--------------------------------------------------------------------------==
// Top-level interrupt handling
/// Global Interrupt Descriptor Table instance
/// Our global IDT.
static IDT: Mutex<Idt> = Mutex::new(Idt::new());

/// Kernel interrupt-handling function.
///
/// Assembly interrupt handlers call into this, and it dispatches interrupts to
/// the appropriate consumers.
#[no_mangle]
pub extern "C" fn handle_interrupt(state: &InterruptContext) {
    let id = state.int_id;
   match id {
       // System timer
       0x20 => { /* TODO: make this work */ }
       // Keyboard
     , 0x21 => {
         // TODO: dispatch keypress event to subscribers (NYI)
           if let Some(input) = keyboard::read_char() {
               if input == '\r' {
                   println!("");
               } else {
                   print!("{}", input);
               }
           }
       }
       // Loonix syscall vector
     , 0x80 => { // TODO: currently, we do nothing here, do we want
                 // our syscalls on this vector as well?
       }
     , _ => panic!("Unknown interrupt: #{} Sorry!", id)
   }
   // send the PICs the end interrupt signal
   unsafe { pics::end_pic_interrupt(id as u8) };
}

/// Handle a CPU exception with a given interrupt context.
#[no_mangle]
pub extern "C" fn handle_cpu_exception(state: &InterruptContext, err_code: usize) -> ! {
    let id = state.int_id;
    let ex_info = &EXCEPTIONS[id];
    let cr_state = control_regs::dump();
    let _ = write!( CONSOLE.lock()
                          .set_colors(Color::White, Color::Blue)
                        //   .clear()
                  , "CPU EXCEPTION {}: {}\n\
                     {} on vector {} with error code {:#x}\n\
                     Source: {}.\nThis is fine.\n\n"
                  , ex_info.mnemonic, ex_info.name, ex_info.irq_type
                  , id, err_code
                  , ex_info.source );

    // TODO: parse error codes
    let _ = match id {
        14 => unimplemented!() //TODO: special handling for page faults
       , _ => write!( CONSOLE.lock()
                             .set_colors(Color::White, Color::Blue)
                    , "Registers:\n{:?}\n    {}\n"
                    , state.registers
                    , cr_state
                    )
    };

    loop { }
}

/// Initialize interrupt handling.
///
/// This function initializes the PICs, populates the IDT with interrupt
/// handlers, loads the IDT pointer, and enables interrupts.
///
/// This is called from the kernel during the init process.
pub unsafe fn initialize() {
   // println!(" . Enabling interrupts:" );
   // println!( " . . Initialising PICs {:>40}"
   //         , pics::initialize().unwrap_or("[ FAIL ]") );
   pics::initialize();
   IDT.lock()
      .add_handlers()
      .load();                 // Load the IDT pointer
   // print!("Testing interrupt handling...");
   // asm!("int $0" :: "N" (0x80));
   // println!("   [DONE]");
   Idt::enable_interrupts(); // enable interrupts

}

bitflags! {
    flags PageFaultErrorCode: u32 {
        const PRESENT = 1 << 0
      , const READ_WRITE = 1 << 1
    }

}
<commit_msg>[x86_all] add bitflags for page fault error codes<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Intterupt handling on x86 machines.
//!
//! This module provides support for interrupt handling on both `x86` and
//! `x86_64` as a black box. Code that depends on this can use the same API
//! regardless of system word size.
use core::fmt;
use core::fmt::Write;

use arch::cpu::{control_regs, Registers};
use arch::cpu::dtable::DTable;

use io::term::CONSOLE;
use io::keyboard;

use vga::Color;

use spin::Mutex;

pub mod idt;
pub mod pics;

use self::idt::Idt;

/// State stored when handling an interrupt.
#[repr(C, packed)]
pub struct InterruptContext { /// callee-saved registers
                              pub registers: Registers
                            , /// interrupt ID number
                              pub int_id: usize
                            //, _pad_1: u32
                            //, /// error number
                            //  pub err_no:  u32
                            //, _pad_2: u32
                            }

//impl InterruptContext {
//    /// Fetches the corresponding CPU exception for this interrupt, if this
//    /// interrupt is a CPU exception.
//    #[inline]
//
//}

#[derive(Debug)]
pub struct ExceptionInfo { pub name: &'static str
                         , pub mnemonic: &'static str
                         , pub irq_type: &'static str
                         , pub source: &'static str
                         }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: [ExceptionInfo; 20]
    = [ ExceptionInfo { name: "Divide-By-Zero Error"
                      , mnemonic: "#DE", irq_type: "Fault"
                      , source: "DIV or IDIV instruction" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "#DB", irq_type: "Fault/trap"
                      , source: "Reserved for Intel use" }
      , ExceptionInfo { name: "Non-Maskable Interrupt"
                      , mnemonic: "NMI", irq_type: "Interrupt"
                      , source: "Non-maskable external interrupt" }
      , ExceptionInfo { name: "Breakpoint"
                      , mnemonic: "#BP", irq_type: "Trap"
                      , source: "INT 3 instruction" }
      , ExceptionInfo { name: "Overflow"
                      , mnemonic: "#OF", irq_type: "Trap"
                      , source: "INTO instruction" }
      , ExceptionInfo { name: "BOUND Range Exceeded"
                      , mnemonic: "#BR", irq_type: "Fault"
                      , source: "BOUND instruction" }
      , ExceptionInfo { name: "Undefined Opcode"
                     , mnemonic: "#UD", irq_type: "Fault"
                     , source: "UD2 instruction or reserved opcode" }
      , ExceptionInfo { name: "Device Not Available"
                      , mnemonic: "#NM", irq_type: "Fault"
                      , source: "Floating-point or WAIT/FWAIT instruction\
                                 (no math coprocessor)" }
      , ExceptionInfo { name: "Double Fault"
                      , mnemonic: "#DF", irq_type: "Abort"
                      , source: "Any instruction that can generate an\
                                 exception, a NMI, or an INTR" }
      , ExceptionInfo { name: "Coprocessor Segment Overrun"
                      , mnemonic: "", irq_type: "Fault"
                      , source: "Any floating-point instruction" }
      , ExceptionInfo { name: "Invalid TSS"
                      , mnemonic: "#TS", irq_type: "Fault"
                      , source: "Task switch or TSS access" }
      , ExceptionInfo { name: "Segment Not Present"
                      , mnemonic: "#NP", irq_type: "Fault"
                      , source: "Loading segment registers or accessing\
                                 system segments" }
      , ExceptionInfo { name: "Stack-Segment Fault"
                      , mnemonic: "#SS", irq_type: "Fault"
                      , source: "Stack operations and SS register loads" }
      , ExceptionInfo { name: "General Protection"
                      , mnemonic: "#GP", irq_type: "Fault"
                      , source: "Any memory reference or other protection\
                                 checks" }
      , ExceptionInfo { name: "Page Fault"
                      , mnemonic: "#PF", irq_type: "Fault"
                      , source: "Any memory reference" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "", irq_type: ""
                      , source: "RESERVED FOR INTEL USE \n This should never \
                                 happen. Something is very wrong." }
      , ExceptionInfo { name: "x87 FPU Floating-Point Error (Math Fault)"
                      , mnemonic: "#MF", irq_type: "Fault"
                      , source: "x87 FPU floating-point or WAIT/FWAIT\
                                 instruction" }
      , ExceptionInfo { name: "Alignment Check"
                      , mnemonic: "#AC", irq_type: "Fault"
                      , source: "Any data reference in memory" }
      , ExceptionInfo { name: "Machine Check"
                      , mnemonic: "#MC", irq_type: "Abort"
                      , source: "Model-dependent" }
      , ExceptionInfo { name: "SIMD Floating-Point Exception"
                      , mnemonic: "#XM", irq_type: "Fault"
                      , source: "SSE/SSE2/SSE3 floating-point instructions" }
       ];

//==--------------------------------------------------------------------------==
// Top-level interrupt handling
/// Global Interrupt Descriptor Table instance
/// Our global IDT.
static IDT: Mutex<Idt> = Mutex::new(Idt::new());

/// Kernel interrupt-handling function.
///
/// Assembly interrupt handlers call into this, and it dispatches interrupts to
/// the appropriate consumers.
#[no_mangle] #[inline(never)]
pub extern "C" fn handle_interrupt(state: &InterruptContext) {
    let id = state.int_id;
   match id {
       // System timer
       0x20 => { /* TODO: make this work */ }
       // Keyboard
     , 0x21 => {
         // TODO: dispatch keypress event to subscribers (NYI)
           if let Some(input) = keyboard::read_char() {
               if input == '\r' {
                   println!("");
               } else {
                   print!("{}", input);
               }
           }
       }
       // Loonix syscall vector
     , 0x80 => { // TODO: currently, we do nothing here, do we want
                 // our syscalls on this vector as well?
       }
     , _ => panic!("Unknown interrupt: #{} Sorry!", id)
   }
   // send the PICs the end interrupt signal
   unsafe { pics::end_pic_interrupt(id as u8) };
}

/// Handle a CPU exception with a given interrupt context.
#[no_mangle] #[inline(never)]
pub extern "C" fn handle_cpu_exception( state: &InterruptContext
                                      , err_code: usize) -> ! {
    let id = state.int_id;
    let ex_info = &EXCEPTIONS[id];
    let cr_state = control_regs::dump();
    let _ = write!( CONSOLE.lock()
                          .set_colors(Color::White, Color::Blue)
                        //   .clear()
                  , "CPU EXCEPTION {}: {}\n\
                     {} on vector {} with error code {:#x}\n\
                     Source: {}.\nThis is fine.\n\n"
                  , ex_info.mnemonic, ex_info.name, ex_info.irq_type
                  , id, err_code
                  , ex_info.source );

    // TODO: parse error codes
    let _ = match id {
        14 => unimplemented!() //TODO: special handling for page faults
       , _ => write!( CONSOLE.lock()
                             .set_colors(Color::White, Color::Blue)
                    , "Registers:\n{:?}\n    {}\n"
                    , state.registers
                    , cr_state
                    )
    };

    loop { }
}

/// Initialize interrupt handling.
///
/// This function initializes the PICs, populates the IDT with interrupt
/// handlers, loads the IDT pointer, and enables interrupts.
///
/// This is called from the kernel during the init process.
pub unsafe fn initialize() {
   // println!(" . Enabling interrupts:" );
   // println!( " . . Initialising PICs {:>40}"
   //         , pics::initialize().unwrap_or("[ FAIL ]") );
   pics::initialize();
   IDT.lock()
      .add_handlers()
      .load();                 // Load the IDT pointer
   // print!("Testing interrupt handling...");
   // asm!("int $0" :: "N" (0x80));
   // println!("   [DONE]");
   Idt::enable_interrupts(); // enable interrupts

}

bitflags! {
    flags PageFaultErrorCode: u32 {
        /// If 1, the error was caused by a page that was present.
        /// Otherwise, the page was non-present.
        const PRESENT = 1 << 0
      , /// If 1, the error was caused by a read. If 0, the cause was a write.
        const READ_WRITE = 1 << 1
      , /// If 1, the error was caused during user-mode execution.
        /// If 0, the processor was in kernel mode.
        const USER_MODE = 1 << 2
      , /// If 1, the fault was caused by reserved bits set to 1 during a fetch.
        const RESERVED = 1 << 3
      , /// If 1, the fault was caused during an instruction fetch.
        const INST_FETCH = 1 << 4
      , /// If 1, there was a protection key violation.
        const PROTECTION = 1 << 5
    }
}

impl fmt::Display for PageFaultErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!( f, "Caused by {}{}{} during a {}{} executing in {} mode."
              , if self.contains(PRESENT) { "a present page" }
                else { "a non-present page" }
              , if self.contains(PROTECTION) { " protection-key violation" }
                else { "" }
              , if self.contains(RESERVED) { " reserved bits set to one "}
                else { "" }
              , if self.contains(READ_WRITE) { "read" } else { "write" }
              , if self.contains(INST_FETCH) { " in an instruction fetch"}
                else { "" }
              , if self.contains(USER_MODE) { "user" } else { "kernel" }            )
    }
}
<|endoftext|>