<commit_before>
use byteorder::{ByteOrder, LittleEndian};

use std;

use gameboy;
use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::gfx::{Color, Frame, GpuMode, GpuStat, SpriteShape};

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,
    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    pub ly: u8,
    pub lyc: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: isize,

    pub frame: Frame,
    pub backbuffer: Frame,
    pub mode: GpuMode,

    counter: u8,
    bg_tile_base: usize,
    window_tile_base: usize,
    background_base: usize,
    window_base: usize,
    sprite_shape: SpriteShape,
    sprites_enabled: bool,
    background_enabled: bool,
    window_enabled: bool,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(gameboy::gfx::VRAM_SIZE),
            sprite_data: Memory::new(gameboy::gfx::SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            backbuffer: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
            bg_tile_base: 0x00,
            window_tile_base: 0x00,
            background_base: 0xC00,
            window_base: 0x00,
            sprite_shape: SpriteShape::Square,
            sprites_enabled: true,
            background_enabled: true,
            window_enabled: true,
        }
    }

    pub fn reset(&mut self) {
        *self = Gpu::new();
    }

    fn set_status(&mut self, irq: &mut Irq) {
        if !self.enabled {
            self.cycles = 0x1C8;
            self.ly = 0x00;
            self.stat = GpuStat::from_u8(0xFD);
        }

        let current_mode = self.mode.clone();

        if self.ly >= 0x90 {
            self.mode = GpuMode::VBlank;
        } else {
            if self.cycles >= 0x178 {
                self.mode = GpuMode::SearchingRam;
            } else if self.cycles >= 0xCC {
                self.mode = GpuMode::TransferringData;
            } else {
                self.mode = GpuMode::HBlank;
            }
        }

        if self.mode != current_mode {
            irq.request(Interrupt::Lcd);
        }

        self.check_coincidence(irq);
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        self.set_status(irq);

        let cycles = cycles as isize;
        if self.enabled {
            self.cycles -= cycles;
        } else {
            return Ok(());
        }

        if self.cycles <= 0 {
            self.ly += 0x01;

            self.cycles = 0x1C8;

            if self.ly == 0x90 {
                irq.request(Interrupt::Vblank);
            } else if self.ly > 0x99 {
                self.ly = 0x00;
            } else if self.ly < 0x90 {
                self.render_scanline();
            }
        }

        Ok(())
    }

    fn render_scanline(&mut self) {
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        // self.clear_scanline(line);
        self.render_background(line);
        self.render_window(line);
        self.render_sprites(line);
        self.frame = self.backbuffer.clone();
    }

    fn clear_scanline(&mut self, line: usize) {
        for i in 0..160 {
            self.backbuffer.pixels[line * 160 + i] = Color::new(0xFF, 0xFF, 0xFF, 0xFF);
        }
    }

    fn render_background(&mut self, line: usize) {
        let bg_base = self.background_base;
        let tile_base = self.bg_tile_base;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..gameboy::SCREEN_WIDTH {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number = self.ram[bg_base + (bg_map_row * 0x20 + bg_map_col)] as usize;

            let line_offset = (line % 0x08) << 0x01;

            let tile_data_start = tile_base +
                                  (if tile_base == 0x00 {
                raw_tile_number
            } else {
                (raw_tile_number as i8 as i16 + 0x80) as usize
            }) * 0x10 + line_offset;

            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.backbuffer.pixels[self.ly as usize * 160 + i as usize] = c;
        }
    }

    fn render_window(&mut self, line: usize) {
        requires!(self.window_enabled);
        requires!(line >= self.window_y as usize);

        let bg_base = self.window_base;
        let tile_base = self.bg_tile_base;
        let bg_map_row = ((line - self.window_y as usize) / 0x08) as usize;
        for i in 0..gameboy::SCREEN_WIDTH {
            if i < self.window_x as u32 {
                continue;
            }
            let x = i as u8 - self.window_x;
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number = self.ram[bg_base + (bg_map_row * 0x20 + bg_map_col)] as usize;

            let line_offset = (line % 0x08) << 0x01;

            let tile_data_start = tile_base +
                                  (if tile_base == 0x00 {
                raw_tile_number
            } else {
                (raw_tile_number as i8 as i16 + 0x80) as usize
            }) * 0x10 + line_offset;

            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.backbuffer.pixels[self.ly as usize * 160 + i as usize] = c;
        }
    }

    fn render_sprites(&mut self, line: usize) {
        requires!(self.sprites_enabled);

        for i in 0..40 {
            let sprite_table_entry_base = i * 0x04;
            let s_y = self.sprite_data[sprite_table_entry_base] as i16 - 0x10;
            let s_x = self.sprite_data[sprite_table_entry_base + 0x01] as i16 - 0x08;
            let sprite_height = if let SpriteShape::Rectangle = self.sprite_shape {
                0x10
            } else {
                0x08
            };

            if s_y <= line as i16 && (s_y + sprite_height as i16) > line as i16 {
                let tile_number = self.sprite_data[sprite_table_entry_base + 0x02] as i16;
                let attributes = self.sprite_data[sprite_table_entry_base + 0x03];
                let above_background = attributes & 0x80 == 0x00;
                let flip_y = attributes & 0x40 == 0x40;
                let flip_x = attributes & 0x20 == 0x20;

                let sprite_y = (line as i16 - s_y) << 0x01;
                let tile_data_start = (tile_number * 0x10) + sprite_y;
                for x in 0..8 {
                    if s_x + x < 0 || s_x + x >= 160 {
                        continue;
                    }
                    let shift = if flip_x { x } else { 0x07 - x };
                    let tile_data1 = (self.ram[tile_data_start as usize] >> shift) & 0x01;
                    let tile_data2 = (self.ram[tile_data_start as usize + 0x01] >> shift) & 0x01;
                    let total_row_data = (tile_data2 << 1) | tile_data1;
                    let color_value = total_row_data;
                    if color_value == 0x00 {
                        continue;
                    }
                    let c = self.get_sprite_color_for_byte(color_value as u8,
                                                           ((attributes & 0x10) >> 0x04) as u8);
                    self.backbuffer.pixels[line as usize * 160 + (s_x as usize + x as usize)] = c;
                }
            }
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    fn get_sprite_color_for_byte(&self, b: u8, palette_entry: u8) -> Color {
        let palette = if palette_entry == 0x00 {
            self.palette0
        } else {
            self.palette1
        };

        let palette_index = match b {
            0x00 => palette & 0x0003,
            0x01 => (palette & 0x000C) >> 0x02,
            0x02 => (palette & 0x0030) >> 0x04,
            0x03 => (palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => {
                self.control_register = val;
                self.enabled = self.control_register & 0x80 == 0x80;
                self.bg_tile_base = if self.control_register & 0x10 == 0x10 {
                    0x00
                } else {
                    0x800
                };
                self.window_base = if self.control_register & 0x40 == 0x40 {
                    0x1C00
                } else {
                    0x1800
                };
                self.background_base = if self.control_register & 0x08 == 0x08 {
                    0x1C00
                } else {
                    0x1800
                };
                self.sprite_shape = if self.control_register & 0x04 == 0x04 {
                    SpriteShape::Rectangle
                } else {
                    SpriteShape::Square
                };
                self.window_enabled = self.control_register & 0x20 == 0x20;
                self.sprites_enabled = self.control_register & 0x02 == 0x02;
                self.background_enabled = self.control_register & 0x01 == 0x01;
            }
            0x41 => self.stat = GpuStat::from_u8(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => (),
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let addr = addr as usize;
        LittleEndian::write_u16(&mut self.ram[addr..], val)
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }
}
<commit_msg>Re-order GPU fields so public ones are first<commit_after>
use byteorder::{ByteOrder, LittleEndian};

use std;

use gameboy;
use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::gfx::{Color, Frame, GpuMode, GpuStat, SpriteShape};

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,

    pub ly: u8,
    pub lyc: u8,

    pub frame: Frame,
    pub backbuffer: Frame,
    pub mode: GpuMode,

    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: isize,

    counter: u8,
    bg_tile_base: usize,
    window_tile_base: usize,
    background_base: usize,
    window_base: usize,
    sprite_shape: SpriteShape,
    sprites_enabled: bool,
    background_enabled: bool,
    window_enabled: bool,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(gameboy::gfx::VRAM_SIZE),
            sprite_data: Memory::new(gameboy::gfx::SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            backbuffer: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
            bg_tile_base: 0x00,
            window_tile_base: 0x00,
            background_base: 0xC00,
            window_base: 0x00,
            sprite_shape: SpriteShape::Square,
            sprites_enabled: true,
            background_enabled: true,
            window_enabled: true,
        }
    }

    pub fn reset(&mut self) {
        *self = Gpu::new();
    }

    fn set_status(&mut self, irq: &mut Irq) {
        if !self.enabled {
            self.cycles = 0x1C8;
            self.ly = 0x00;
            self.stat = GpuStat::from_u8(0xFD);
        }

        let current_mode = self.mode.clone();

        if self.ly >= 0x90 {
            self.mode = GpuMode::VBlank;
        } else {
            if self.cycles >= 0x178 {
                self.mode = GpuMode::SearchingRam;
            } else if self.cycles >= 0xCC {
                self.mode = GpuMode::TransferringData;
            } else {
                self.mode = GpuMode::HBlank;
            }
        }

        if self.mode != current_mode {
            irq.request(Interrupt::Lcd);
        }

        self.check_coincidence(irq);
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        self.set_status(irq);

        let cycles = cycles as isize;
        if self.enabled {
            self.cycles -= cycles;
        } else {
            return Ok(());
        }

        if self.cycles <= 0 {
            self.ly += 0x01;

            self.cycles = 0x1C8;

            if self.ly == 0x90 {
                irq.request(Interrupt::Vblank);
            } else if self.ly > 0x99 {
                self.ly = 0x00;
            } else if self.ly < 0x90 {
                self.render_scanline();
            }
        }

        Ok(())
    }

    fn render_scanline(&mut self) {
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        // self.clear_scanline(line);
        self.render_background(line);
        self.render_window(line);
        self.render_sprites(line);
        self.frame = self.backbuffer.clone();
    }

    fn clear_scanline(&mut self, line: usize) {
        for i in 0..160 {
            self.backbuffer.pixels[line * 160 + i] = Color::new(0xFF, 0xFF, 0xFF, 0xFF);
        }
    }

    fn render_background(&mut self, line: usize) {
        let bg_base = self.background_base;
        let tile_base = self.bg_tile_base;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..gameboy::SCREEN_WIDTH {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number = self.ram[bg_base + (bg_map_row * 0x20 + bg_map_col)] as usize;

            let line_offset = (line % 0x08) << 0x01;

            let tile_data_start = tile_base +
                                  (if tile_base == 0x00 {
                raw_tile_number
            } else {
                (raw_tile_number as i8 as i16 + 0x80) as usize
            }) * 0x10 + line_offset;

            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.backbuffer.pixels[self.ly as usize * 160 + i as usize] = c;
        }
    }

    fn render_window(&mut self, line: usize) {
        requires!(self.window_enabled);
        requires!(line >= self.window_y as usize);

        let bg_base = self.window_base;
        let tile_base = self.bg_tile_base;
        let bg_map_row = ((line - self.window_y as usize) / 0x08) as usize;
        for i in 0..gameboy::SCREEN_WIDTH {
            if i < self.window_x as u32 {
                continue;
            }
            let x = i as u8 - self.window_x;
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number = self.ram[bg_base + (bg_map_row * 0x20 + bg_map_col)] as usize;

            let line_offset = (line % 0x08) << 0x01;

            let tile_data_start = tile_base +
                                  (if tile_base == 0x00 {
                raw_tile_number
            } else {
                (raw_tile_number as i8 as i16 + 0x80) as usize
            }) * 0x10 + line_offset;

            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.backbuffer.pixels[self.ly as usize * 160 + i as usize] = c;
        }
    }

    fn render_sprites(&mut self, line: usize) {
        requires!(self.sprites_enabled);

        for i in 0..40 {
            let sprite_table_entry_base = i * 0x04;
            let s_y = self.sprite_data[sprite_table_entry_base] as i16 - 0x10;
            let s_x = self.sprite_data[sprite_table_entry_base + 0x01] as i16 - 0x08;
            let sprite_height = if let SpriteShape::Rectangle = self.sprite_shape {
                0x10
            } else {
                0x08
            };

            if s_y <= line as i16 && (s_y + sprite_height as i16) > line as i16 {
                let tile_number = self.sprite_data[sprite_table_entry_base + 0x02] as i16;
                let attributes = self.sprite_data[sprite_table_entry_base + 0x03];
                let above_background = attributes & 0x80 == 0x00;
                let flip_y = attributes & 0x40 == 0x40;
                let flip_x = attributes & 0x20 == 0x20;

                let sprite_y = (line as i16 - s_y) << 0x01;
                let tile_data_start = (tile_number * 0x10) + sprite_y;
                for x in 0..8 {
                    if s_x + x < 0 || s_x + x >= 160 {
                        continue;
                    }
                    let shift = if flip_x { x } else { 0x07 - x };
                    let tile_data1 = (self.ram[tile_data_start as usize] >> shift) & 0x01;
                    let tile_data2 = (self.ram[tile_data_start as usize + 0x01] >> shift) & 0x01;
                    let total_row_data = (tile_data2 << 1) | tile_data1;
                    let color_value = total_row_data;
                    if color_value == 0x00 {
                        continue;
                    }
                    let c = self.get_sprite_color_for_byte(color_value as u8,
                                                           ((attributes & 0x10) >> 0x04) as u8);
                    self.backbuffer.pixels[line as usize * 160 + (s_x as usize + x as usize)] = c;
                }
            }
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    fn get_sprite_color_for_byte(&self, b: u8, palette_entry: u8) -> Color {
        let palette = if palette_entry == 0x00 {
            self.palette0
        } else {
            self.palette1
        };

        let palette_index = match b {
            0x00 => palette & 0x0003,
            0x01 => (palette & 0x000C) >> 0x02,
            0x02 => (palette & 0x0030) >> 0x04,
            0x03 => (palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => {
                self.control_register = val;
                self.enabled = self.control_register & 0x80 == 0x80;
                self.bg_tile_base = if self.control_register & 0x10 == 0x10 {
                    0x00
                } else {
                    0x800
                };
                self.window_base = if self.control_register & 0x40 == 0x40 {
                    0x1C00
                } else {
                    0x1800
                };
                self.background_base = if self.control_register & 0x08 == 0x08 {
                    0x1C00
                } else {
                    0x1800
                };
                self.sprite_shape = if self.control_register & 0x04 == 0x04 {
                    SpriteShape::Rectangle
                } else {
                    SpriteShape::Square
                };
                self.window_enabled = self.control_register & 0x20 == 0x20;
                self.sprites_enabled = self.control_register & 0x02 == 0x02;
                self.background_enabled = self.control_register & 0x01 == 0x01;
            }
            0x41 => self.stat = GpuStat::from_u8(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => (),
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let addr = addr as usize;
        LittleEndian::write_u16(&mut self.ram[addr..], val)
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }
}
<|endoftext|>


<commit_before>use error::BrokerError;
use futures::future::{self, Future};
use handlers::return_to_relier;
use http::{self, Service, ContextHandle, HandlerResult};
use hyper::{Method};
use hyper::header::{ContentType};
use hyper::server::{Request, Response};
use oidc_bridge;

/// Request handler for OAuth callbacks
///
/// After the user allows or denies the Authentication Request with the famous
/// identity provider, they will be redirected back to the callback handler.
///
/// For providers that don't support `response_type=form_post`, we capture the
/// fragment parameters in javascript and emulate the POST request.
///
/// Once we have a POST request, we can verify the callback data and return the
/// resulting token to the relying party, or error.
pub fn callback(service: &Service, req: Request, shared_ctx: ContextHandle) -> HandlerResult {
    match *req.method() {
        Method::Get => {
            let res = Response::new()
                .with_header(ContentType::html())
                .with_body(service.app.templates.fragment_callback.render(&[]));
            Box::new(future::ok(res))
        },
        Method::Post => {
            let f = http::parse_form_encoded_body(req.body());

            let app = service.app.clone();
            let f = f.and_then(move |mut params| {
                let state = try_get_param!(params, "state");
                let id_token = try_get_param!(params, "id_token");

                let result = app.store.get_session("oidc", &state);
                future::result(result.map(|stored| (app, stored, id_token)))
            });

            let ctx = shared_ctx.clone();
            let f = f.and_then(move |(app, stored, id_token)| {
                ctx.borrow_mut().redirect_uri = Some(
                    stored["redirect"].parse().expect("redirect_uri missing from session"));

                oidc_bridge::verify(app.clone(), stored, id_token)
                    .map(move |jwt| (app, ctx, jwt))
            });

            let f = f.and_then(|(app, ctx, jwt)| {
                let ctx = ctx.borrow();
                return_to_relier(&*app, &ctx, &[("id_token", &jwt)])
            });

            Box::new(f)
        },
        _ => unreachable!(),
    }
}
<commit_msg>Small doc fix<commit_after>use error::BrokerError;
use futures::future::{self, Future};
use handlers::return_to_relier;
use http::{self, Service, ContextHandle, HandlerResult};
use hyper::{Method};
use hyper::header::{ContentType};
use hyper::server::{Request, Response};
use oidc_bridge;

/// Request handler for OAuth callbacks
///
/// After the user allows or denies the Authentication Request with the famous
/// identity provider, they will be redirected back to the callback handler.
///
/// For providers that don't support `response_mode=form_post`, we capture the
/// fragment parameters in javascript and emulate the POST request.
///
/// Once we have a POST request, we can verify the callback data and return the
/// resulting token to the relying party, or error.
pub fn callback(service: &Service, req: Request, shared_ctx: ContextHandle) -> HandlerResult {
    match *req.method() {
        Method::Get => {
            let res = Response::new()
                .with_header(ContentType::html())
                .with_body(service.app.templates.fragment_callback.render(&[]));
            Box::new(future::ok(res))
        },
        Method::Post => {
            let f = http::parse_form_encoded_body(req.body());

            let app = service.app.clone();
            let f = f.and_then(move |mut params| {
                let state = try_get_param!(params, "state");
                let id_token = try_get_param!(params, "id_token");

                let result = app.store.get_session("oidc", &state);
                future::result(result.map(|stored| (app, stored, id_token)))
            });

            let ctx = shared_ctx.clone();
            let f = f.and_then(move |(app, stored, id_token)| {
                ctx.borrow_mut().redirect_uri = Some(
                    stored["redirect"].parse().expect("redirect_uri missing from session"));

                oidc_bridge::verify(app.clone(), stored, id_token)
                    .map(move |jwt| (app, ctx, jwt))
            });

            let f = f.and_then(|(app, ctx, jwt)| {
                let ctx = ctx.borrow();
                return_to_relier(&*app, &ctx, &[("id_token", &jwt)])
            });

            Box::new(f)
        },
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use compositor_task::{CompositorEventListener, CompositorReceiver};
use compositor_task::{InitialCompositorState, Msg};
use euclid::scale_factor::ScaleFactor;
use euclid::{Point2D, Size2D};
use msg::constellation_msg::AnimationState;
use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::{ConstellationChan, WindowSizeData};
use profile_traits::mem;
use profile_traits::time;
use windowing::WindowEvent;

/// Starts the compositor, which listens for messages on the specified port.
///
/// This is the null compositor which doesn't draw anything to the screen.
/// It's intended for headless testing.
pub struct NullCompositor {
    /// The port on which we receive messages.
    pub port: Box<CompositorReceiver>,
    /// A channel to the constellation.
    constellation_chan: ConstellationChan,
    /// A channel to the time profiler.
    time_profiler_chan: time::ProfilerChan,
    /// A channel to the memory profiler.
    mem_profiler_chan: mem::ProfilerChan,
}

impl NullCompositor {
    fn new(state: InitialCompositorState) -> NullCompositor {
        NullCompositor {
            port: state.receiver,
            constellation_chan: state.constellation_chan,
            time_profiler_chan: state.time_profiler_chan,
            mem_profiler_chan: state.mem_profiler_chan,
        }
    }

    pub fn create(state: InitialCompositorState) -> NullCompositor {
        let compositor = NullCompositor::new(state);

        // Tell the constellation about the initial fake size.
        {
            let ConstellationChan(ref chan) = compositor.constellation_chan;
            chan.send(ConstellationMsg::ResizedWindow(WindowSizeData {
                initial_viewport: Size2D::typed(640_f32, 480_f32),
                visible_viewport: Size2D::typed(640_f32, 480_f32),
                device_pixel_ratio: ScaleFactor::new(1.0),
            })).unwrap();
        }

        compositor
    }
}

impl CompositorEventListener for NullCompositor {
    fn handle_events(&mut self, _: Vec<WindowEvent>) -> bool {
        match self.port.recv_compositor_msg() {
            Msg::Exit(chan) => {
                debug!("shutting down the constellation");
                let ConstellationChan(ref con_chan) = self.constellation_chan;
                con_chan.send(ConstellationMsg::Exit).unwrap();
                chan.send(()).unwrap();
            }

            Msg::ShutdownComplete => {
                debug!("constellation completed shutdown");
                return false
            }

            Msg::GetNativeDisplay(chan) => {
                chan.send(None).unwrap();
            }

            Msg::SetFrameTree(_, response_chan, _) => {
                response_chan.send(()).unwrap();
            }

            Msg::GetClientWindow(send) => {
               let rect = (Size2D::zero(), Point2D::zero());
                send.send(rect).unwrap();
            }

            Msg::ChangeRunningAnimationsState(pipeline_id, animation_state) => {
                match animation_state {
                    AnimationState::AnimationsPresent |
                    AnimationState::NoAnimationsPresent |
                    AnimationState::NoAnimationCallbacksPresent => {}
                    AnimationState::AnimationCallbacksPresent => {
                        let msg = ConstellationMsg::TickAnimation(pipeline_id);
                        self.constellation_chan.0.send(msg).unwrap()
                    }
                }
            }

            // Explicitly list ignored messages so that when we add a new one,
            // we'll notice and think about whether it needs a response, like
            // SetFrameTree.

            Msg::InitializeLayersForPipeline(..) |
            Msg::AssignPaintedBuffers(..) |
            Msg::ScrollFragmentPoint(..) |
            Msg::Status(..) |
            Msg::LoadStart(..) |
            Msg::LoadComplete(..) |
            Msg::ScrollTimeout(..) |
            Msg::RecompositeAfterScroll |
            Msg::ChangePageTitle(..) |
            Msg::ChangePageUrl(..) |
            Msg::KeyEvent(..) |
            Msg::SetCursor(..) |
            Msg::ViewportConstrained(..) => {}
            Msg::CreatePng(..) |
            Msg::PaintTaskExited(..) |
            Msg::MoveTo(..) |
            Msg::ResizeTo(..) |
            Msg::IsReadyToSaveImageReply(..) => {}
            Msg::NewFavicon(..) => {}
            Msg::HeadParsed => {}
            Msg::ReturnUnusedNativeSurfaces(..) => {}
            Msg::CollectMemoryReports(..) => {}
            Msg::PipelineExited(..) => {}
            Msg::CreateLayerForSubpage(..) => {}
        }
        true
    }

    fn repaint_synchronously(&mut self) {}

    fn shutdown(&mut self) {
        // Drain compositor port, sometimes messages contain channels that are blocking
        // another task from finishing (i.e. SetIds)
        while self.port.try_recv_compositor_msg().is_some() {}

        self.time_profiler_chan.send(time::ProfilerMsg::Exit);
        self.mem_profiler_chan.send(mem::ProfilerMsg::Exit);
    }

    fn pinch_zoom_level(&self) -> f32 {
        1.0
    }

    fn title_for_main_frame(&self) {}
}
<commit_msg>Auto merge of #7805 - mbrubeck:headless-dpr, r=mrobinson<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use compositor_task::{CompositorEventListener, CompositorReceiver};
use compositor_task::{InitialCompositorState, Msg};
use euclid::scale_factor::ScaleFactor;
use euclid::{Point2D, Size2D};
use msg::constellation_msg::AnimationState;
use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::{ConstellationChan, WindowSizeData};
use profile_traits::mem;
use profile_traits::time;
use util::opts;
use windowing::WindowEvent;

/// Starts the compositor, which listens for messages on the specified port.
///
/// This is the null compositor which doesn't draw anything to the screen.
/// It's intended for headless testing.
pub struct NullCompositor {
    /// The port on which we receive messages.
    pub port: Box<CompositorReceiver>,
    /// A channel to the constellation.
    constellation_chan: ConstellationChan,
    /// A channel to the time profiler.
    time_profiler_chan: time::ProfilerChan,
    /// A channel to the memory profiler.
    mem_profiler_chan: mem::ProfilerChan,
}

impl NullCompositor {
    fn new(state: InitialCompositorState) -> NullCompositor {
        NullCompositor {
            port: state.receiver,
            constellation_chan: state.constellation_chan,
            time_profiler_chan: state.time_profiler_chan,
            mem_profiler_chan: state.mem_profiler_chan,
        }
    }

    pub fn create(state: InitialCompositorState) -> NullCompositor {
        let compositor = NullCompositor::new(state);

        // Tell the constellation about the initial fake size.
        {
            let ConstellationChan(ref chan) = compositor.constellation_chan;
            chan.send(ConstellationMsg::ResizedWindow(WindowSizeData {
                initial_viewport: Size2D::typed(800_f32, 600_f32),
                visible_viewport: Size2D::typed(800_f32, 600_f32),
                device_pixel_ratio:
                    ScaleFactor::new(opts::get().device_pixels_per_px.unwrap_or(1.0)),
            })).unwrap();
        }

        compositor
    }
}

impl CompositorEventListener for NullCompositor {
    fn handle_events(&mut self, _: Vec<WindowEvent>) -> bool {
        match self.port.recv_compositor_msg() {
            Msg::Exit(chan) => {
                debug!("shutting down the constellation");
                let ConstellationChan(ref con_chan) = self.constellation_chan;
                con_chan.send(ConstellationMsg::Exit).unwrap();
                chan.send(()).unwrap();
            }

            Msg::ShutdownComplete => {
                debug!("constellation completed shutdown");
                return false
            }

            Msg::GetNativeDisplay(chan) => {
                chan.send(None).unwrap();
            }

            Msg::SetFrameTree(_, response_chan, _) => {
                response_chan.send(()).unwrap();
            }

            Msg::GetClientWindow(send) => {
               let rect = (Size2D::zero(), Point2D::zero());
                send.send(rect).unwrap();
            }

            Msg::ChangeRunningAnimationsState(pipeline_id, animation_state) => {
                match animation_state {
                    AnimationState::AnimationsPresent |
                    AnimationState::NoAnimationsPresent |
                    AnimationState::NoAnimationCallbacksPresent => {}
                    AnimationState::AnimationCallbacksPresent => {
                        let msg = ConstellationMsg::TickAnimation(pipeline_id);
                        self.constellation_chan.0.send(msg).unwrap()
                    }
                }
            }

            // Explicitly list ignored messages so that when we add a new one,
            // we'll notice and think about whether it needs a response, like
            // SetFrameTree.

            Msg::InitializeLayersForPipeline(..) |
            Msg::AssignPaintedBuffers(..) |
            Msg::ScrollFragmentPoint(..) |
            Msg::Status(..) |
            Msg::LoadStart(..) |
            Msg::LoadComplete(..) |
            Msg::ScrollTimeout(..) |
            Msg::RecompositeAfterScroll |
            Msg::ChangePageTitle(..) |
            Msg::ChangePageUrl(..) |
            Msg::KeyEvent(..) |
            Msg::SetCursor(..) |
            Msg::ViewportConstrained(..) => {}
            Msg::CreatePng(..) |
            Msg::PaintTaskExited(..) |
            Msg::MoveTo(..) |
            Msg::ResizeTo(..) |
            Msg::IsReadyToSaveImageReply(..) => {}
            Msg::NewFavicon(..) => {}
            Msg::HeadParsed => {}
            Msg::ReturnUnusedNativeSurfaces(..) => {}
            Msg::CollectMemoryReports(..) => {}
            Msg::PipelineExited(..) => {}
            Msg::CreateLayerForSubpage(..) => {}
        }
        true
    }

    fn repaint_synchronously(&mut self) {}

    fn shutdown(&mut self) {
        // Drain compositor port, sometimes messages contain channels that are blocking
        // another task from finishing (i.e. SetIds)
        while self.port.try_recv_compositor_msg().is_some() {}

        self.time_profiler_chan.send(time::ProfilerMsg::Exit);
        self.mem_profiler_chan.send(mem::ProfilerMsg::Exit);
    }

    fn pinch_zoom_level(&self) -> f32 {
        1.0
    }

    fn title_for_main_frame(&self) {}
}
<|endoftext|>


<commit_before>use std::io;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use cast;

use quic::errors::{Error, Result};
use quic::utils::map_unexpected_eof;

pub const FRAME_FLAG_STREAM: u8 = 0b10000000;

#[derive(Clone, Debug, Default, PartialEq)]
pub struct StreamFrame {
    pub stream_id: u32,
    pub offset: u64,
    pub stream_data: Vec<u8>,
    pub fin: bool,
}

impl StreamFrame {
    pub fn encode(&self, write: &mut io::Write, last_frame: bool) -> Result<()> {
        // construct the type octet
        let mut frame_type = FRAME_FLAG_STREAM;

        if self.fin {
            frame_type |= 0b01000000
        }

        if !last_frame {
            frame_type |= 0b00100000;
        }

        // TODO: calculate this more intelligently
        let offset_size = 8;
        frame_type |= 0b00011100;

        // TODO: calculate this more intelligently
        let stream_id_size = 4;
        frame_type |= 0b00000011;

        write.write_u8(frame_type)?;

        // other fields
        assert!(self.stream_data.len() != 0 || self.fin);

        if !last_frame {
            write.write_u16::<BigEndian>(
                cast::u16(self.stream_data.len())
                .expect("Stream data too big, size has to fit in 16 bits")
            )?;
        }
        write.write_uint::<BigEndian>(self.stream_id as u64, stream_id_size)?;
        write.write_uint::<BigEndian>(self.offset, offset_size)?;
        write.write_all(&self.stream_data[..])?;

        Ok(())
    }

    pub fn decode(read: &mut io::Read) -> Result<StreamFrame> {
        // extract type octet data
        let frame_type = read.read_u8().map_err(map_unexpected_eof)?;
        assert!((frame_type & FRAME_FLAG_STREAM) != 0);

        let fin = (frame_type & 0b01000000) != 0;

        let last_frame = (frame_type & 0b00100000) == 0;

        let offset_size = match (frame_type & 0b00011100) >> 2 {
            0b000 => 0,
            bit_value => bit_value + 1,
        } as usize;

        let stream_id_size = ((frame_type & 0b00000011) + 1) as usize;

        // other fields
        let data_length = if !last_frame {
            Some(read.read_u16::<BigEndian>().map_err(map_unexpected_eof)? as usize)
        } else {
            None
        };

        let stream_id =
            read.read_uint::<BigEndian>(stream_id_size)
            .map_err(map_unexpected_eof)?
            as u32;

        let offset = if offset_size != 0 {
            read.read_uint::<BigEndian>(offset_size)
            .map_err(map_unexpected_eof)?
        } else {
            0
        };

        let stream_data = match data_length {
            Some(data_length) => {
                let mut buffer = vec![0; data_length];
                read.read_exact(&mut buffer).map_err(map_unexpected_eof)?;
                buffer
            },
            None => {
                let mut buffer = Vec::new();
                read.read_to_end(&mut buffer).map_err(map_unexpected_eof)?;
                buffer
            },
        };

        if stream_data.len() == 0 && !fin {
            return Err(Error::Decoding(String::from("Must have either non-zero data length or the FIN bit set")));
        }

        Ok(StreamFrame {
            stream_id: stream_id,
            offset: offset,
            stream_data: stream_data,
            fin: fin,
        })
    }
}
<commit_msg>Formatting<commit_after>use std::io;

use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use cast;

use quic::errors::{Error, Result};
use quic::utils::map_unexpected_eof;

pub const FRAME_FLAG_STREAM: u8 = 0b10000000;

#[derive(Clone, Debug, Default, PartialEq)]
pub struct StreamFrame {
    pub stream_id: u32,
    pub offset: u64,
    pub stream_data: Vec<u8>,
    pub fin: bool,
}

impl StreamFrame {
    pub fn encode(&self, write: &mut io::Write, last_frame: bool) -> Result<()> {
        // construct the type octet
        let mut frame_type = FRAME_FLAG_STREAM;

        if self.fin {
            frame_type |= 0b01000000
        }

        if !last_frame {
            frame_type |= 0b00100000;
        }

        // TODO: calculate this more intelligently
        let offset_size = 8;
        frame_type |= 0b00011100;

        // TODO: calculate this more intelligently
        let stream_id_size = 4;
        frame_type |= 0b00000011;

        write.write_u8(frame_type)?;

        // other fields
        assert!(self.stream_data.len() != 0 || self.fin);

        if !last_frame {
            write.write_u16::<BigEndian>(
                cast::u16(self.stream_data.len())
                .expect("Stream data too big, size has to fit in 16 bits")
            )?;
        }
        write.write_uint::<BigEndian>(self.stream_id as u64, stream_id_size)?;
        write.write_uint::<BigEndian>(self.offset, offset_size)?;
        write.write_all(&self.stream_data[..])?;

        Ok(())
    }

    pub fn decode(read: &mut io::Read) -> Result<StreamFrame> {
        // extract type octet data
        let frame_type = read.read_u8().map_err(map_unexpected_eof)?;
        assert!((frame_type & FRAME_FLAG_STREAM) != 0);

        let fin = (frame_type & 0b01000000) != 0;

        let last_frame = (frame_type & 0b00100000) == 0;

        let offset_size = match (frame_type & 0b00011100) >> 2 {
            0b000 => 0,
            bit_value => bit_value + 1,
        } as usize;

        let stream_id_size = ((frame_type & 0b00000011) + 1) as usize;

        // other fields
        let data_length = if !last_frame {
            Some(read.read_u16::<BigEndian>().map_err(map_unexpected_eof)? as usize)
        } else {
            None
        };

        let stream_id =
            read.read_uint::<BigEndian>(stream_id_size)
            .map_err(map_unexpected_eof)?
            as u32;

        let offset = if offset_size != 0 {
            read.read_uint::<BigEndian>(offset_size)
            .map_err(map_unexpected_eof)?
        } else {
            0
        };

        let stream_data = match data_length {
            Some(data_length) => {
                let mut buffer = vec![0; data_length];
                read.read_exact(&mut buffer).map_err(map_unexpected_eof)?;
                buffer
            },
            None => {
                let mut buffer = Vec::new();
                read.read_to_end(&mut buffer).map_err(map_unexpected_eof)?;
                buffer
            },
        };

        if stream_data.len() == 0 && !fin {
            return Err(
                Error::Decoding(
                    String::from("Must have either non-zero data length or the FIN bit set")
                )
            );
        }

        Ok(StreamFrame {
            stream_id: stream_id,
            offset: offset,
            stream_data: stream_data,
            fin: fin,
        })
    }
}
<|endoftext|>


<commit_before>extern crate serenity;

use serenity::prelude::*;
use serenity::model::*;
use std::env;

struct Handler;

impl EventHandler for Handler {
    // Set a handler for the `on_message` event - so that whenever a new message
    // is received - the closure (or function) passed will be called.
    //
    // Event handlers are dispatched through multi-threading, and so multiple
    // of a single event can be dispatched simultaneously.
    fn message(&self, _: Context, msg: Message) {
        if msg.content == "!ping" {
            // Sending a message can fail, due to a network error, an
            // authentication error, or lack of permissions to post in the
            // channel, so log to stdout when some error happens, with a
            // description of it.
            if let Err(why) = msg.channel_id.say("Pong!") {
                println!("Error sending message: {:?}", why);
            }
        }
    }

    // Set a handler to be called on the `on_ready` event. This is called when a
    // shard is booted, and a READY payload is sent by Discord. This payload
    // contains data like the current user's guild Ids, current user data,
    // private channels, and more.
    //
    // In this case, just print what the current user's username is.
    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");

    // Create a new instance of the Client, logging in as a bot. This will
    // automatically prepend your bot token with "Bot ", which is a requirement
    // by Discord for bot users.
    let mut client = Client::new(&token, Handler).expect("Err creating client");

    // Finally, start a single shard, and start listening to events.
    //
    // Shards will automatically attempt to reconnect, and will perform
    // exponential backoff until it reconnects.
    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}
<commit_msg>Clarify some example 01 documentation<commit_after>extern crate serenity;

use serenity::prelude::*;
use serenity::model::*;
use std::env;

struct Handler;

impl EventHandler for Handler {
    // Set a handler for the `message` event - so that whenever a new message
    // is received - the closure (or function) passed will be called.
    //
    // Event handlers are dispatched through a threadpool, and so multiple
    // events can be dispatched simultaneously.
    fn message(&self, _: Context, msg: Message) {
        if msg.content == "!ping" {
            // Sending a message can fail, due to a network error, an
            // authentication error, or lack of permissions to post in the
            // channel, so log to stdout when some error happens, with a
            // description of it.
            if let Err(why) = msg.channel_id.say("Pong!") {
                println!("Error sending message: {:?}", why);
            }
        }
    }

    // Set a handler to be called on the `ready` event. This is called when a
    // shard is booted, and a READY payload is sent by Discord. This payload
    // contains data like the current user's guild Ids, current user data,
    // private channels, and more.
    //
    // In this case, just print what the current user's username is.
    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");

    // Create a new instance of the Client, logging in as a bot. This will
    // automatically prepend your bot token with "Bot ", which is a requirement
    // by Discord for bot users.
    let mut client = Client::new(&token, Handler).expect("Err creating client");

    // Finally, start a single shard, and start listening to events.
    //
    // Shards will automatically attempt to reconnect, and will perform
    // exponential backoff until it reconnects.
    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}
<|endoftext|>


<commit_before>use super::trees::*;
use crate::ram::types::Id;

raft_state_machine! {
    def qry locate_key(entry: EntryKey) -> Id;
    def cmd split(tree: Id, new_tree: Id, pivot: EntryKey);
    // No subscription for clients
}
<commit_msg>sketching master tree for ranged index<commit_after>use super::trees::*;
use std::collections::BTreeMap;
use crate::ram::types::Id;
use futures::prelude::*;
use bifrost::raft::state_machine::StateMachineCtl;
use bifrost::utils;
use bifrost::raft::RaftService;

pub struct MasterTreeSM {
    tree: BTreeMap<EntryKey, Id>,
    sm_id: u64
}

raft_state_machine! {
    def qry locate_key(entry: EntryKey) -> Id;
    def cmd split(new_tree: Id, pivot: EntryKey);
    // No subscription for clients
}

impl StateMachineCmds for MasterTreeSM {
    fn locate_key(&self, entry: EntryKey) -> BoxFuture<Id> {
        future::ready(
            self.tree.range(entry..)
            .next()
            .map(|(_, id)| *id)
            .unwrap()
        ).boxed()
    }

    fn split(&mut self, new_tree: Id, pivot: EntryKey) -> BoxFuture<()> {
        self.tree.insert(pivot, new_tree);
        future::ready(()).boxed()
    }
}

impl StateMachineCtl for MasterTreeSM {
    raft_sm_complete!();
    fn id(&self) -> u64 {
        self.sm_id
    }
    fn snapshot(&self) -> Option<Vec<u8>> {
        Some(utils::serde::serialize(&self.tree))
    }
    fn recover(&mut self, data: Vec<u8>) -> BoxFuture<()> {
        let tree = utils::serde::deserialize(&data).unwrap();
        self.tree = tree;
        future::ready(()).boxed()
    }
}<|endoftext|>


<commit_before>/// RouteGraph defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot, tag, and channel.
/// Edges are also allowed to go to null, in which case they only have a destination slot and
/// channel. These are outputs.
/// Edges can also COME from null, in which case the source has the format (slot, channel)

use super::effect::Effect;
use super::graphwatcher::GraphWatcher;

use std::collections::hash_set::HashSet;
use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::rc::Rc;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct EdgeWeight {
    from_slot: u32,
    from_ch: u8,
    to_slot: u32,
    to_ch: u8,
}

#[derive(Eq, PartialEq)]
enum NodeData {
    Effect(Rc<Effect>),
    Graph(DagHandle),
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct DagHandle {
    id: u32,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct PrimNodeHandle {
    id: u64,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct NodeHandle {
    dag_handle: DagHandle,
    node_handle: Option<PrimNodeHandle>,
}

#[derive(Clone, Hash, Eq, PartialEq)]
pub struct Edge {
    dag_handle: DagHandle,
    from: Option<PrimNodeHandle>,
    to: Option<PrimNodeHandle>,
    weight: EdgeWeight,
}

pub struct RouteGraph {
    // TODO: can make these non-zero for more efficient Option<NodeHandle> encoding
    dag_counter: u32,
    node_counter: u64,
    watchers: Vec<Box<GraphWatcher>>,
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        RouteGraph {
            dag_counter: 0,
            node_counter: 0,
            watchers: Vec::new(),
            edges: HashMap::new(),
            node_data: HashMap::new(),
        }
    }
    pub fn add_watcher(&mut self, mut watcher: Box<GraphWatcher>, do_replay: bool) {
        if do_replay {
            for node in self.iter_nodes() {
                watcher.on_add_node(node);
            }
            for edge in self.iter_edges() {
                watcher.on_add_edge(edge);
            }
        }
        self.watchers.push(watcher);
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=&NodeHandle> + 'a {
        self.node_data.keys()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn add_dag(&mut self) -> DagHandle {
        let handle = DagHandle{ id: self.dag_counter };
        self.dag_counter += 1;
        handle
    }
    pub fn add_node(&mut self, dag: DagHandle, node_data: NodeData) -> NodeHandle {
        let primhandle = PrimNodeHandle { id: self.node_counter };
        let handle = NodeHandle {
            dag_handle: dag,
            node_handle: Some(primhandle),
        };
        self.node_counter = self.node_counter+1;
        // Create storage for the node's outgoing edges
        // Panic if the NodeHandle was somehow already in use.
        assert!(self.edges.insert(handle, EdgeSet::new()).is_none());
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data).is_none());
        for w in &mut self.watchers {
            w.on_add_node(&handle);
        }
        handle
    }
    pub fn add_edge(&mut self, edge: Edge) -> Result<(), ()> {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        // Locate all nodes that alias to this DAG:
        /*let aliased_nodes = self.edges.iter().filter(|&(k, v)| {
            k.dag_handle == edge.dag_handle
        });
        let edges_to_check = aliased_nodes.flat_map(|(k, v)| {
            v.outbound.iter()
        });*/
        // If a cycle was introduced (
        unimplemented!();
        /*let ok_to_add = {
            let ref dag = self.dags[edge.dag_handle()];
            dag.can_add_edge(edge.edge(),
                &|e1, e2| self.are_node_slots_connected(
                    dag.node_data(e1.to().unwrap()),
                    e1.weight().to_slot, e1.weight().to_ch,
                    e2.weight().from_slot, e2.weight().from_ch
                )
            )
        };
        if let Ok(_) = ok_to_add {
            // only notify watchers on a successful operation.
            for w in &mut self.watchers {
                w.on_add_edge(&edge);
            }
            let mut mdag = self.dags.get_mut(edge.dag_handle()).unwrap();
            mdag.add_edge_unchecked(edge.edge);
        }
        ok_to_add*/
    }
    fn is_edge_reachable(&self, from: &Edge, to: &Edge) -> bool {
        let dag_handle = from.dag_handle.clone();
        let dagnode_handle = NodeHandle::new(dag_handle, None);
        for candidate in self.edges[&from.to_full()].outbound.iter() {
            if self.are_edges_internally_connected(&self.node_data[&candidate.from_full()], &from, &candidate) {
                // See if we can reach `to` from the candidate
                match candidate.to {
                    // The edge we traversed keeps us inside the current DAG
                    Some(_) => if self.is_edge_reachable(candidate, to) {
                        return true
                    },
                    // The edge we traversed takes us out of the DAG.
                    // Consider all nodes aliased to this DAG;
                    //   for each one, consider all paths that lead back to it & continue the
                    //   search.
                    None => {
                        let search = NodeData::Graph(candidate.dag_handle);
                        for node in self.node_data_to_handles(&search) {
                            for edge_out in self.edges[&node].outbound.iter() {
                                // Consider all edges leaving this node that are reachable
                                if edge_out.weight.from_slot == to.weight.to_slot &&
                                    edge_out.weight.from_ch == to.weight.to_ch {
                                    for edge_in in self.paths_from_edge_to_node(edge_out, &node) {
                                        for edge in self.edges[&dagnode_handle].inbound.iter() {
                                            // Follow the edge back into this DAG.
                                            if edge_in.weight.to_slot == edge.weight.from_slot &&
                                                edge_in.weight.to_ch == edge.weight.from_ch {
                                                // Now we're back in the DAG; continue the search
                                                if self.is_edge_reachable(&edge, to) {
                                                    return true
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        false
    }
    /// Return all edges into `to` that are reachable from `from`.
    fn paths_from_edge_to_node<'a>(&'a self, from: &'a Edge, to: &'a NodeHandle) -> impl Iterator<Item=&'a Edge> + 'a {
        self.edges[to].inbound.iter().filter(move |e| {
            self.is_edge_reachable(&from, e)
        })
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, node_data: &NodeData, from: &Edge, to: &Edge) -> bool {
        match *node_data {
            NodeData::Effect(ref effect) => effect.are_slots_connected(
                from.weight.to_slot, from.weight.to_ch,
                to.weight.from_slot, to.weight.from_ch),
            // See if there's a path from (None->from.to) to (to.from->None) within the dag
            NodeData::Graph(ref dag_handle) => {
                let dagnode_handle = NodeHandle::new(dag_handle.clone(), None);
                // Consider all edges from (None->from.to)
                self.edges[&dagnode_handle].outbound.iter().filter(|new_from| {
                    new_from.weight.from_slot == from.weight.to_slot &&
                        new_from.weight.from_ch == from.weight.to_ch
                })
                // Check if there's a path to (None) and that the edge to (None) is (to.from->None)
                .any(|new_from| {
                    self.paths_from_edge_to_node(new_from, &dagnode_handle).any(|new_to| {
                        new_to.weight.to_slot == to.weight.from_slot &&
                            new_to.weight.to_ch == to.weight.from_ch
                    })
                })
            }
        }
    }
    fn node_data_to_handles<'a>(&'a self, data: &'a NodeData) -> impl Iterator<Item=NodeHandle> + 'a {
        self.node_data.iter().filter(move |&(handle, node)| {
            node == data
        }).map(|(handle, node)| {
            handle.clone()
        })
    }
    /*fn toplevel_dag(&self) -> &DagImpl {
        &self.dags[&DagHandle{ id: 0 }]
    }*/
    /*fn are_node_slots_connected(&self, data: &NodeData, in_slot: u32, in_ch: u8, out_slot: u32, out_ch: u8) -> bool {
        unimplemented!();
        match *data {
            // TODO: for now, consider all inputs tied to all outputs for each graph.
            // In future, may enforce constraints or actually calculate the connections,
            // but this requires careful planning due to aliasing.
            NodeData::Graph(ref dag_handle) => true,
            NodeData::Effect(ref effect) => effect.are_slots_connected(in_slot, in_ch, out_slot, out_ch)
        }
    }*/
    /// Returns true if there's a path from `in` to `out`.
    pub fn are_slots_connected(&self, in_slot: u32, in_ch: u8, out_slot: u32, out_ch: u8) -> bool {
        unimplemented!();
        /*
        let mut are_connected = false;
        assert!(self.dags.len() == 1); // no nested DAGs
        self.toplevel_dag().traverse(&mut |edge| {
            // ensure we have no nested DAGs.
            assert!(edge.to().map(|to| self.toplevel_dag().node_data(to).is_effect()).unwrap_or(true));
            let do_follow = edge.from() != &None || edge.weight().from_slot == in_slot && edge.weight().from_ch == in_ch;
            if do_follow && edge.weight().to_slot == out_slot && edge.weight().to_ch == out_ch {
                are_connected = true;
            }
            do_follow
        });
        are_connected*/
    }
    pub fn del_node(&mut self, node: NodeHandle) -> Result<(), ()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(())
                }
            }
        };
        if let Ok(_) = ok_to_delete {
            // delete the data associated with this node
            self.node_data.remove(&node);
            // notify watchers of successful deletion
            for w in &mut self.watchers {
                w.on_del_node(&node);
            }
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
        for w in &mut self.watchers {
            w.on_del_edge(&edge);
        }
    }
}

impl NodeHandle {
    fn new(dag: DagHandle, node: Option<PrimNodeHandle>) -> Self {
        Self {
            dag_handle: dag,
            node_handle: node,
        }
    }
    fn dag_handle(&self) -> &DagHandle {
        &self.dag_handle
    }
    fn node_handle(&self) -> &Option<PrimNodeHandle> {
        &self.node_handle
    }
}

impl Edge {
    fn new(dag: DagHandle) -> Self {
        unimplemented!();
        /*Self {
            dag_handle: dag,
            edge: edge,
        }*/
    }
    fn dag_handle(&self) -> &DagHandle {
        &self.dag_handle
    }
    fn from_full(&self) -> NodeHandle {
        NodeHandle {
            dag_handle: self.dag_handle,
            node_handle: self.from,
        }
    }
    fn to_full(&self) -> NodeHandle {
        NodeHandle {
            dag_handle: self.dag_handle,
            node_handle: self.to,
        }
    }
}

impl NodeData {
    fn is_effect(&self) -> bool {
        match *self {
            NodeData::Effect(_) => true,
            _ => false,
        }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty()
    }
}
<commit_msg>Implement all remaining methods for base DAG operation<commit_after>/// RouteGraph defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot, tag, and channel.
/// Edges are also allowed to go to null, in which case they only have a destination slot and
/// channel. These are outputs.
/// Edges can also COME from null, in which case the source has the format (slot, channel)

use super::effect::Effect;
use super::graphwatcher::GraphWatcher;

use std::collections::hash_set::HashSet;
use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::rc::Rc;

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct EdgeWeight {
    from_slot: u32,
    from_ch: u8,
    to_slot: u32,
    to_ch: u8,
}

#[derive(Eq, PartialEq)]
enum NodeData {
    Effect(Rc<Effect>),
    Graph(DagHandle),
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct DagHandle {
    // None represents the Top-level DAG
    id: Option<u32>,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct PrimNodeHandle {
    id: u64,
}

#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub struct NodeHandle {
    dag_handle: DagHandle,
    node_handle: Option<PrimNodeHandle>,
}

#[derive(Clone, Hash, Eq, PartialEq)]
pub struct Edge {
    dag_handle: DagHandle,
    from: Option<PrimNodeHandle>,
    to: Option<PrimNodeHandle>,
    weight: EdgeWeight,
}

pub struct RouteGraph {
    // TODO: can make these non-zero for more efficient Option<NodeHandle> encoding
    dag_counter: u32,
    node_counter: u64,
    watchers: Vec<Box<GraphWatcher>>,
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        RouteGraph {
            dag_counter: 0,
            node_counter: 0,
            watchers: Vec::new(),
            edges: HashMap::new(),
            node_data: HashMap::new(),
        }
    }
    pub fn add_watcher(&mut self, mut watcher: Box<GraphWatcher>, do_replay: bool) {
        if do_replay {
            for node in self.iter_nodes() {
                watcher.on_add_node(node);
            }
            for edge in self.iter_edges() {
                watcher.on_add_edge(edge);
            }
        }
        self.watchers.push(watcher);
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=&NodeHandle> + 'a {
        self.node_data.keys()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn add_dag(&mut self) -> DagHandle {
        let handle = DagHandle{ id: Some(self.dag_counter) };
        self.dag_counter += 1;
        handle
    }
    pub fn add_node(&mut self, dag: DagHandle, node_data: NodeData) -> NodeHandle {
        let primhandle = PrimNodeHandle { id: self.node_counter };
        let handle = NodeHandle {
            dag_handle: dag,
            node_handle: Some(primhandle),
        };
        self.node_counter = self.node_counter+1;
        // Create storage for the node's outgoing edges
        // Panic if the NodeHandle was somehow already in use.
        assert!(self.edges.insert(handle, EdgeSet::new()).is_none());
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data).is_none());
        for w in &mut self.watchers {
            w.on_add_node(&handle);
        }
        handle
    }
    pub fn add_edge(&mut self, edge: Edge) -> Result<(), ()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(())
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, to: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        let dag_handle = from.dag_handle.clone();
        let dagnode_handle = NodeHandle::new(dag_handle, None);
        for candidate in self.edges[&from.to_full()].outbound.iter() {
            if self.are_edges_internally_connected(&self.node_data[&candidate.from_full()], &from, &candidate) {
                // See if we can reach `to` from the candidate
                match candidate.to {
                    // The edge we traversed keeps us inside the current DAG
                    Some(_) => if self.is_edge_reachable(candidate, to) {
                        return true
                    },
                    // The edge we traversed takes us out of the DAG.
                    // Consider all nodes aliased to this DAG;
                    //   for each one, consider all paths that lead back to it & continue the
                    //   search.
                    None => {
                        let search = NodeData::Graph(candidate.dag_handle);
                        for node in self.node_data_to_handles(&search) {
                            for edge_out in self.edges[&node].outbound.iter() {
                                // Consider all edges leaving this node that are reachable
                                if edge_out.weight.from_slot == to.weight.to_slot &&
                                    edge_out.weight.from_ch == to.weight.to_ch {
                                    for edge_in in self.paths_from_edge_to_node(edge_out, &node) {
                                        for edge in self.edges[&dagnode_handle].inbound.iter() {
                                            // Follow the edge back into this DAG.
                                            if edge_in.weight.to_slot == edge.weight.from_slot &&
                                                edge_in.weight.to_ch == edge.weight.from_ch {
                                                // Now we're back in the DAG; continue the search
                                                if self.is_edge_reachable(&edge, to) {
                                                    return true
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        false
    }
    /// Return all edges into `to` that are reachable from `from`.
    fn paths_from_edge_to_node<'a>(&'a self, from: &'a Edge, to: &'a NodeHandle) -> impl Iterator<Item=&'a Edge> + 'a {
        self.edges[to].inbound.iter().filter(move |e| {
            self.is_edge_reachable(&from, e)
        })
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, node_data: &NodeData, from: &Edge, to: &Edge) -> bool {
        match *node_data {
            NodeData::Effect(ref effect) => effect.are_slots_connected(
                from.weight.to_slot, from.weight.to_ch,
                to.weight.from_slot, to.weight.from_ch),
            // See if there's a path from (None->from.to) to (to.from->None) within the dag
            NodeData::Graph(ref dag_handle) => {
                let dagnode_handle = NodeHandle::new(dag_handle.clone(), None);
                // Consider all edges from (None->from.to)
                self.edges[&dagnode_handle].outbound.iter().filter(|new_from| {
                    new_from.weight.from_slot == from.weight.to_slot &&
                        new_from.weight.from_ch == from.weight.to_ch
                })
                // Check if there's a path to (None) and that the edge to (None) is (to.from->None)
                .any(|new_from| {
                    self.paths_from_edge_to_node(new_from, &dagnode_handle).any(|new_to| {
                        new_to.weight.to_slot == to.weight.from_slot &&
                            new_to.weight.to_ch == to.weight.from_ch
                    })
                })
            }
        }
    }
    fn node_data_to_handles<'a>(&'a self, data: &'a NodeData) -> impl Iterator<Item=NodeHandle> + 'a {
        self.node_data.iter().filter(move |&(handle, node)| {
            node == data
        }).map(|(handle, node)| {
            handle.clone()
        })
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, in_ch: u8, out_slot: u32, out_ch: u8) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::new(DagHandle { id: None }, None);
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot && edge.weight.from_ch == in_ch
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot && edge.weight.to_ch == out_ch
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> Result<(), ()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(())
                }
            }
        };
        if let Ok(_) = ok_to_delete {
            // delete the data associated with this node
            self.node_data.remove(&node);
            // notify watchers of successful deletion
            for w in &mut self.watchers {
                w.on_del_node(&node);
            }
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
        for w in &mut self.watchers {
            w.on_del_edge(&edge);
        }
    }
}

impl NodeHandle {
    fn new(dag: DagHandle, node: Option<PrimNodeHandle>) -> Self {
        Self {
            dag_handle: dag,
            node_handle: node,
        }
    }
    fn dag_handle(&self) -> &DagHandle {
        &self.dag_handle
    }
    fn node_handle(&self) -> &Option<PrimNodeHandle> {
        &self.node_handle
    }
}

impl Edge {
    fn dag_handle(&self) -> &DagHandle {
        &self.dag_handle
    }
    fn from_full(&self) -> NodeHandle {
        NodeHandle {
            dag_handle: self.dag_handle,
            node_handle: self.from,
        }
    }
    fn to_full(&self) -> NodeHandle {
        NodeHandle {
            dag_handle: self.dag_handle,
            node_handle: self.to,
        }
    }
}

impl NodeData {
    fn is_effect(&self) -> bool {
        match *self {
            NodeData::Effect(_) => true,
            _ => false,
        }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}
<|endoftext|>