<commit_before>
extern crate clap;
extern crate intcode;

// Time Start: Sun, 15 Dec 2019 00:56:30 -0500
// Time Finish 1: Sun, 15 Dec 2019 03:10:37 -0500 (2 hours, 14 minutes, 7 seconds)
// Time Finish 2:
// Time Total:

use clap::{Arg, App};

use intcode::Intcode;

use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::fmt;

#[derive(Copy, Clone)]
struct BBox(i64,i64,i64,i64);// xmin, xmax, ymin, ymax
impl BBox {
    pub fn new() -> BBox {
        BBox(0,0,0,0)
    }

    pub fn xmin(&self) -> i64 { self.0 }
    pub fn xmax(&self) -> i64 { self.1 }
    pub fn ymin(&self) -> i64 { self.2 }
    pub fn ymax(&self) -> i64 { self.3 }

    pub fn update(&mut self, x: i64, y: i64) {
        if x < self.0 { self.0 = x; }
        if x > self.1 { self.1 = x; }
        if y < self.2 { self.2 = y; }
        if y > self.3 { self.3 = y; }
    }
}
impl fmt::Display for BBox {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "BBox: {}, {}, {}, {}", self.0, self.1, self.2, self.3)
    }
}

struct Droid {
    pub pos: (i64, i64),
    pub map: HashMap<(i64, i64), char>,
    pub bbox: BBox,
    ctrl: Intcode,
}
impl Droid {
    pub fn new(ctrl: Intcode) -> Droid {
        let mut map = HashMap::new();
        map.insert((0,0), '.');
        Droid {
            pos: (0, 0),
            map: map,
            bbox: BBox::new(),
            ctrl: ctrl,
        }
    }

    pub fn item_at(&self, x: i64, y: i64) -> char {
        match self.map.get(&(x,y)) {
            Some(x) => *x,
            None    => ' ',
        }
    }

    pub fn put(&mut self, x: i64, y: i64, obj: char) {
        self.bbox.update(x, y);
        self.map.insert((x, y), obj);
    }

    pub fn follow_path(&mut self, path: &Vec<u8>) -> Option<char> {
        for (i, dir) in path.iter().enumerate() {
            let (x, y) = match dir {
                1 => (self.pos.0, self.pos.1 + 1), // North
                2 => (self.pos.0, self.pos.1 - 1), // South
                3 => (self.pos.0 - 1, self.pos.1), // West
                4 => (self.pos.0 + 1, self.pos.1), // East
                _ => unreachable!("Invalid dir {}", dir),
            };
            self.ctrl.pipe(*dir as i64);
            while self.ctrl.output_len() < 1 && self.ctrl.step() { }
            if self.ctrl.is_halted() { return None; }
            match self.ctrl.shift_output() {
                Some(0) => {
                    self.put(x, y, '#');
                    if i == path.len()-1 { break } else { return None };
                },
                Some(1) => { self.put(x, y, '.'); },
                Some(2) => { self.put(x, y, 'O'); },
                Some(x) => unreachable!("Unexpected output: {}", x),
                _ => unreachable!("Unexpected output: None"),
            };
            self.pos.0 = x;
            self.pos.1 = y;
        }
        return Some(self.item_at(self.pos.0, self.pos.1));
    }

    pub fn search_for_oxygen_system(&mut self) -> Option<Vec<u8>> {
        // Want to stay close to 0, 0 so we find the shortest path.
        // Therefore, we always start our search for a new tile at out origin
        let (x0, y0) = self.pos;
        loop {
            let (x, y, path0) = self.find_nearest(x0, y0, |_x, _y, ch| ch == ' ')?; // position closest to start
            let path = self.find_path(self.pos.0, self.pos.1, x, y)?; // shortest path from here to there
            let obj = self.follow_path(&path)?;
            if obj == 'O' { // Found it!
                return Some(path0);
            }
        }
    }

    // Find a path through the known universe between the two given points.
    pub fn find_path(&self, x0: i64, y0: i64, x1: i64, y1: i64) -> Option<Vec<u8>> {
        let (_, _, path) = self.find_nearest(x0, y0, |x, y, _ch| x == x1 && y == y1)?;
        return Some(path);
    }

    // Search known universe for the coordinate of `obj` nearest to the given start coordinate.
    pub fn find_nearest(&self, x: i64, y: i64, test: impl Fn(i64, i64, char) -> bool) -> Option<(i64, i64, Vec<u8>)> {
        let mut todo: VecDeque<(i64, i64, Vec<u8>)> = VecDeque::new();
        let mut seen: HashSet<(i64, i64)> = HashSet::new();
        let mut step: Vec<(i64, i64, u8)> = Vec::new();
        step.push((0,  1, 1)); // North
        step.push((0, -1, 2)); // South
        step.push((-1, 0, 3)); // West
        step.push(( 1, 0, 4)); // East

        todo.push_back((x, y, Vec::new()));
        loop {
            let (x, y, path) = todo.pop_front()?; // or return None
            if test(x, y, self.item_at(x, y)) {
                return Some((x, y, path));
            }
            if '.' == self.item_at(x, y) {
                for i in 0..4 {
                    let (a, b, dir) = step[i];
                    if !seen.contains(&(x+a, y+b)) {
                        let mut newpath = path.clone();
                        newpath.push(dir);
                        todo.push_back((x+a, y+b, newpath));
                    }
                }
            }
            seen.insert((x, y));
        };
    }
}
impl fmt::Display for Droid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for y in (self.bbox.ymin()..=self.bbox.ymax()).rev() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                if let Err(err) = write!(f, "{}", self.item_at(x, y)) {
                    return Err(err);
                }
            }
            if let Err(err) = write!(f, "{}", "\n") {
                return Err(err);
            }
        }
        Ok(())
    }
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 15")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("15.in"));

    let mut droid = Droid::new(Intcode::load(&fname));
    if let Some(path) = droid.search_for_oxygen_system() {
        println!("{}", droid);
        println!("Found path length {}", path.len());
    } else {
        println!("Bummer");
    }
}
<commit_msg>Day 15<commit_after>
extern crate clap;
extern crate intcode;

// Time Start: Sun, 15 Dec 2019 00:56:30 -0500
// Time Finish 1: Sun, 15 Dec 2019 03:10:37 -0500 (2 hours, 14 minutes, 7 seconds)
// Time Finish 2: Sun, 15 Dec 2019 03:42:57 -0500 (32 minutes, 20 seconds)
// Time Total: 2 hours, 46 minutes, 27 seconds

use clap::{Arg, App};

use intcode::Intcode;

use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::fmt;

#[derive(Copy, Clone)]
struct BBox(i64,i64,i64,i64);// xmin, xmax, ymin, ymax
impl BBox {
    pub fn new() -> BBox {
        BBox(0,0,0,0)
    }

    pub fn xmin(&self) -> i64 { self.0 }
    pub fn xmax(&self) -> i64 { self.1 }
    pub fn ymin(&self) -> i64 { self.2 }
    pub fn ymax(&self) -> i64 { self.3 }

    pub fn update(&mut self, x: i64, y: i64) {
        if x < self.0 { self.0 = x; }
        if x > self.1 { self.1 = x; }
        if y < self.2 { self.2 = y; }
        if y > self.3 { self.3 = y; }
    }
}
impl fmt::Display for BBox {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "BBox: {}, {}, {}, {}", self.0, self.1, self.2, self.3)
    }
}

struct Droid {
    pub pos: (i64, i64),
    pub map: HashMap<(i64, i64), char>,
    pub bbox: BBox,
    ctrl: Intcode,
}
impl Droid {
    pub fn new(ctrl: Intcode) -> Droid {
        let mut map = HashMap::new();
        map.insert((0,0), '.');
        Droid {
            pos: (0, 0),
            map: map,
            bbox: BBox::new(),
            ctrl: ctrl,
        }
    }

    pub fn item_at(&self, x: i64, y: i64) -> char {
        match self.map.get(&(x,y)) {
            Some(x) => *x,
            None    => ' ',
        }
    }

    pub fn put(&mut self, x: i64, y: i64, obj: char) {
        self.bbox.update(x, y);
        self.map.insert((x, y), obj);
    }

    pub fn follow_path(&mut self, path: &Vec<u8>) -> Option<char> {
        for (i, dir) in path.iter().enumerate() {
            let (x, y) = match dir {
                1 => (self.pos.0, self.pos.1 + 1), // North
                2 => (self.pos.0, self.pos.1 - 1), // South
                3 => (self.pos.0 - 1, self.pos.1), // West
                4 => (self.pos.0 + 1, self.pos.1), // East
                _ => unreachable!("Invalid dir {}", dir),
            };
            self.ctrl.pipe(*dir as i64);
            while self.ctrl.output_len() < 1 && self.ctrl.step() { }
            if self.ctrl.is_halted() { return None; }
            match self.ctrl.shift_output() {
                Some(0) => {
                    self.put(x, y, '#');
                    if i == path.len()-1 { break } else { return None };
                },
                Some(1) => { self.put(x, y, '.'); },
                Some(2) => { self.put(x, y, 'O'); },
                Some(x) => unreachable!("Unexpected output: {}", x),
                _ => unreachable!("Unexpected output: None"),
            };
            self.pos.0 = x;
            self.pos.1 = y;
        }
        return Some(self.item_at(self.pos.0, self.pos.1));
    }

    pub fn search_for_oxygen_system(&mut self) -> Option<Vec<u8>> {
        // Want to stay close to 0, 0 so we find the shortest path.
        // Therefore, we always start our search for a new tile at out origin
        let (x0, y0) = self.pos;
        loop {
            let (x, y, path0) = self.find_nearest(x0, y0, |_x, _y, ch| ch == ' ')?; // position closest to start
            let path = self.find_path(self.pos.0, self.pos.1, x, y)?; // shortest path from here to there
            let obj = self.follow_path(&path)?;
            if obj == 'O' { // Found it!
                return Some(path0);
            }
        }
    }

    pub fn fill_map(&mut self) -> Option<()> {
        loop {
            let (_, _, path) = self.find_nearest(self.pos.0, self.pos.1, |_x, _y, ch| ch == ' ')?; // position closest to current
            self.follow_path(&path)?;
        }
    }

    // Find a path through the known universe between the two given points.
    pub fn find_path(&self, x0: i64, y0: i64, x1: i64, y1: i64) -> Option<Vec<u8>> {
        let (_, _, path) = self.find_nearest(x0, y0, |x, y, _ch| x == x1 && y == y1)?;
        return Some(path);
    }

    // Search known universe for the coordinate of `obj` nearest to the given start coordinate.
    pub fn find_nearest(&self, x: i64, y: i64, test: impl Fn(i64, i64, char) -> bool) -> Option<(i64, i64, Vec<u8>)> {
        let mut todo: VecDeque<(i64, i64, Vec<u8>)> = VecDeque::new();
        let mut seen: HashSet<(i64, i64)> = HashSet::new();
        let mut step: Vec<(i64, i64, u8)> = Vec::new();
        step.push((0,  1, 1)); // North
        step.push((0, -1, 2)); // South
        step.push((-1, 0, 3)); // West
        step.push(( 1, 0, 4)); // East

        todo.push_back((x, y, Vec::new()));
        loop {
            let (x, y, path) = todo.pop_front()?; // or return None
            if test(x, y, self.item_at(x, y)) {
                return Some((x, y, path));
            }
            if match self.item_at(x, y) { '.' | 'O' => true, _ => false } {
                for i in 0..4 {
                    let (a, b, dir) = step[i];
                    if !seen.contains(&(x+a, y+b)) {
                        let mut newpath = path.clone();
                        newpath.push(dir);
                        todo.push_back((x+a, y+b, newpath));
                    }
                }
            }
            seen.insert((x, y));
        };
    }
}
impl fmt::Display for Droid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        for y in (self.bbox.ymin()..=self.bbox.ymax()).rev() {
            for x in self.bbox.xmin()..=self.bbox.xmax() {
                if let Err(err) = write!(f, "{}", self.item_at(x, y)) {
                    return Err(err);
                }
            }
            if let Err(err) = write!(f, "{}", "\n") {
                return Err(err);
            }
        }
        Ok(())
    }
}

fn time_fill_oxygen(x0: i64, y0: i64, map: &mut HashMap<(i64, i64), char>) -> u64 {
    let mut time = 0_u64;
    let mut todo: VecDeque<(i64, i64, u64)> = VecDeque::new();
    let mut step: Vec<(i64, i64)> = Vec::new();
    step.push((0,  1));
    step.push((0, -1));
    step.push((-1, 0));
    step.push(( 1, 0));

    todo.push_back((x0, y0, 0));
    loop {
        if let Some((x, y, t)) = todo.pop_front() {
            time = t;
            for i in 0..4 {
                let (dx, dy) = step[i];
                let (a, b) = (x+dx, y+dy);
                match map.get(&(a, b)) {
                    Some('.') => {
                        todo.push_back((a, b, t + 1));
                        map.insert((a, b), 'O');
                    },
                    _ => (),
                }
            }
        } else { break; }
    }
    return time;
}

fn main() {
    let matches = App::new("Advent of Code 2019, Day 15")
        .arg(Arg::with_name("FILE")
             .help("Input file to process")
             .index(1))
        .get_matches();
    let fname = String::from(matches.value_of("FILE").unwrap_or("15.in"));

    let mut droid = Droid::new(Intcode::load(&fname));
    if let Some(path) = droid.search_for_oxygen_system() {
        println!("{}", droid);
        println!("Part 1: Found path length {}", path.len());
    } else {
        println!("Bummer");
    }

    // Part 2: a bit less autonomous
    droid.fill_map();
    println!("{}", droid);
    // Get oxygen system location the silly way:
    let (x0, y0, _) = droid.find_nearest(0, 0, |_, _, ch| ch == 'O').unwrap_or_else(|| panic!("Lost the oxygen system again!"));
    // Run the simulation outside the bot object.
    println!("Part 2: Time to fill section: {}", time_fill_oxygen(x0, y0, &mut droid.map.clone()));
}
<|endoftext|>


<commit_before>use definitions::bytecode;
use definitions::typedef::*;
use error::*;
use ieee754::Ieee754;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

// We use CGA for the display resolution
pub const DISPLAY_WIDTH: usize = 320;
pub const DISPLAY_HEIGHT: usize = 200;

/// We can adjust the buffer register count here
pub const BUF_REG_COUNT: usize = 32;

/// A register for displaying color data on a virtual display
struct DisplayRegister {
    color_mode: ColorMode,
    data: [[SmallWord; DISPLAY_HEIGHT]; DISPLAY_WIDTH],
}

/// A register type for comparing two values
struct CompareRegister {
    cmp1: Word,
    cmp2: Word,
}

/// The mode for *interpreting* the color data in the framebuffer
enum ColorMode {
    _1Bit,
    _8Bit,
    _24Bit,
}

/// The whole state of the VM
pub struct VM {
    /// The program counter
    pc: Address,
    /// The currently loaded image
    image: Image,
    /// The stack pointer
    stack_ptr: Address,
    /// The buffer registers
    buf_regs: [Word; BUF_REG_COUNT],
    display_reg: DisplayRegister,
    cmp_reg: CompareRegister,
    stack: Vec<Word>,
}

impl VM {
    pub fn new() -> VM {
        VM {
            pc: 0,
            image: Image::new(),
            stack_ptr: 0,
            buf_regs: [0; BUF_REG_COUNT],
            display_reg: DisplayRegister {
                color_mode: ColorMode::_24Bit,
                data: [[0; DISPLAY_HEIGHT]; DISPLAY_WIDTH],
            },
            cmp_reg: CompareRegister { cmp1: 0, cmp2: 0 },
            stack: Vec::new(),
        }
    }

    pub fn exec<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        let mut image_file = File::open(path).chain_err(|| "unable to open game image")?;
        image_file.read_to_end(&mut self.image).chain_err(|| "unable to read image")?;

        while self.pc < self.image.len() {
            let byte = self.current_byte().chain_err(|| "unable to read current byte")?;

            match byte {
                bytecode::HALT => break,
                bytecode::ADD => self.add().chain_err(|| "unable to execute 'add' instruction")?,
                bytecode::SUB => self.sub().chain_err(|| "unable to execute 'sub' instruction")?,
                bytecode::MUL => self.mul().chain_err(|| "unable to execute 'mul' instruction")?,
                bytecode::DIV => self.div().chain_err(|| "unable to execute 'div' instruction")?,
                bytecode::PUSH => {
                    let res = self.read_word().chain_err(|| "unable to read word")?;

                    self.push_word(res).chain_err(|| "unable to push value to the stack")?;
                }
                bytecode::JMP => {
                    let addr = self.read_word().chain_err(|| "unable to read word")?;

                    self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                    continue;
                }
                bytecode::JZ => {
                    let addr = self.read_word().chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack == 0.0 {
                        self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                        continue;
                    }
                }
                bytecode::JNZ => {
                    let addr = self.read_word().chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack != 0.0 {
                        self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                        continue;
                    }
                }
                _ => bail!("unexpected opcode {:02x} at address {:?}", byte, self.pc),
            }

            self.advance_pc().chain_err(|| "unable to advance program counter")?;
        }

        Ok(())
    }

    fn push_word(&mut self, value: Word) -> VMResult<()> {
        if !self.stack.is_empty() {
            self.stack_ptr += 1;
        }

        self.stack.push(value);

        Ok(())
    }

    fn push_number(&mut self, value: Number) -> VMResult<()> {
        self.push_word(value.bits())
    }

    fn pop_word(&mut self) -> VMResult<Word> {
        if self.stack.is_empty() {
            bail!("unable to pop word off an empty Stack");
        }

        let res = self.stack.remove(self.stack_ptr);
        if !self.stack.is_empty() {
            self.stack_ptr -= 1;
        }

        Ok(res)
    }

    fn pop_number(&mut self) -> VMResult<Number> {
        let top = self.pop_word().chain_err(|| "unable to pop word off the stack")?;
        Ok(Number::from_bits(top))
    }

    fn add(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a + b).chain_err(|| "unable to push value to the stack")?;
        Ok(())
    }

    fn sub(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a - b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn mul(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a * b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn div(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a / b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn jmp(&mut self, addr: Address) -> VMResult<()> {
        self.pc = addr;
        Ok(())
    }

    fn read_word(&mut self) -> VMResult<Word> {
        // Build a Word from single bytes
        let mut res: Word = 0;
        for _ in 0..8 {
            res <<= 8;
            self.advance_pc().chain_err(|| "unable to advance program counter")?;
            let current_byte = self.current_byte().chain_err(|| "unable to read current byte")?;
            res |= current_byte as Word;
        }

        Ok(res)
    }

    fn read_small_word(&mut self) -> VMResult<SmallWord> {
        // Build a Word from single bytes
        let mut res: SmallWord = 0;
        for _ in 0..4 {
            res <<= 8;
            self.advance_pc().chain_err(|| "unable to advance program counter")?;
            let current_byte = self.current_byte().chain_err(|| "unable to read current byte")?;
            res |= current_byte as SmallWord;
        }

        Ok(res)
    }

    fn read_tiny_word(&mut self) -> VMResult<TinyWord> {
        // Build a Word from single bytes
        let mut res: TinyWord = 0;
        for _ in 0..2 {
            res <<= 8;
            self.advance_pc().chain_err(|| "unable to advance program counter")?;
            let current_byte = self.current_byte().chain_err(|| "unable to read current byte")?;
            res |= current_byte as TinyWord;
        }

        Ok(res)
    }

    fn advance_pc(&mut self) -> VMResult<()> {
        self.pc += 1;
        Ok(())
    }

    fn current_byte(&mut self) -> VMResult<Byte> {
        if self.pc < self.image.len() {
            Ok(self.image[self.pc])
        } else {
            bail!("program counter out of bounds");
        }
    }

    fn peek_word(&mut self) -> VMResult<Word> {
        if self.stack_ptr < self.stack.len() {
            Ok(self.stack[self.stack_ptr])
        } else {
            bail!("stack pointer out of bounds");
        }
    }

    fn peek_number(&mut self) -> VMResult<Number> {
        let top = self.peek_word().chain_err(|| "unable to peek for word")?;
        Ok(Number::from_bits(top))
    }
}
<commit_msg>Optimized advance_pc<commit_after>use definitions::bytecode;
use definitions::typedef::*;
use error::*;
use ieee754::Ieee754;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

// We use CGA for the display resolution
pub const DISPLAY_WIDTH: usize = 320;
pub const DISPLAY_HEIGHT: usize = 200;

/// We can adjust the buffer register count here
pub const BUF_REG_COUNT: usize = 32;

/// A register for displaying color data on a virtual display
struct DisplayRegister {
    color_mode: ColorMode,
    data: [[SmallWord; DISPLAY_HEIGHT]; DISPLAY_WIDTH],
}

/// A register type for comparing two values
struct CompareRegister {
    cra: Word,
    crb: Word,
}

/// The mode for *interpreting* the color data in the framebuffer
enum ColorMode {
    _1Bit,
    _8Bit,
    _24Bit,
}

/// The whole state of the VM
pub struct VM {
    /// The program counter
    pc: Address,
    /// The currently loaded image
    image: Image,
    /// The stack pointer
    stack_ptr: Address,
    /// The buffer registers
    buf_regs: [Word; BUF_REG_COUNT],
    display_reg: DisplayRegister,
    cmp_reg: CompareRegister,
    stack: Vec<Word>,
}

impl VM {
    pub fn new() -> VM {
        VM {
            pc: 0,
            image: Image::new(),
            stack_ptr: 0,
            buf_regs: [0; BUF_REG_COUNT],
            display_reg: DisplayRegister {
                color_mode: ColorMode::_24Bit,
                data: [[0; DISPLAY_HEIGHT]; DISPLAY_WIDTH],
            },
            cmp_reg: CompareRegister { cra: 0, crb: 0 },
            stack: Vec::new(),
        }
    }

    pub fn exec<P: AsRef<Path>>(&mut self, path: P) -> VMResult<()> {
        let mut image_file = File::open(path).chain_err(|| "unable to open game image")?;
        image_file.read_to_end(&mut self.image).chain_err(|| "unable to read image")?;

        while self.pc < self.image.len() {
            let byte = self.current_byte().chain_err(|| "unable to read current byte")?;

            match byte {
                bytecode::HALT => break,
                bytecode::ADD => self.add().chain_err(|| "unable to execute 'add' instruction")?,
                bytecode::SUB => self.sub().chain_err(|| "unable to execute 'sub' instruction")?,
                bytecode::MUL => self.mul().chain_err(|| "unable to execute 'mul' instruction")?,
                bytecode::DIV => self.div().chain_err(|| "unable to execute 'div' instruction")?,
                bytecode::PUSH => {
                    let res = self.read_word().chain_err(|| "unable to read word")?;

                    self.push_word(res).chain_err(|| "unable to push value to the stack")?;
                }
                bytecode::JMP => {
                    let addr = self.read_word().chain_err(|| "unable to read word")?;

                    self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                    continue;
                }
                bytecode::JZ => {
                    let addr = self.read_word().chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack == 0.0 {
                        self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                        continue;
                    }
                }
                bytecode::JNZ => {
                    let addr = self.read_word().chain_err(|| "unable to read word")?;

                    let top_of_stack = self.peek_number()
                        .chain_err(|| "unable to get current top of stack")?;

                    if top_of_stack != 0.0 {
                        self.jmp(addr as Address).chain_err(|| "unable to jump")?;
                        continue;
                    }
                }
                _ => bail!("unexpected opcode {:02x} at address {:?}", byte, self.pc),
            }

            self.advance_pc();
        }

        Ok(())
    }

    fn push_word(&mut self, value: Word) -> VMResult<()> {
        if !self.stack.is_empty() {
            self.stack_ptr += 1;
        }

        self.stack.push(value);

        Ok(())
    }

    fn push_number(&mut self, value: Number) -> VMResult<()> {
        self.push_word(value.bits())
    }

    fn pop_word(&mut self) -> VMResult<Word> {
        if self.stack.is_empty() {
            bail!("unable to pop word off an empty Stack");
        }

        let res = self.stack.remove(self.stack_ptr);
        if !self.stack.is_empty() {
            self.stack_ptr -= 1;
        }

        Ok(res)
    }

    fn pop_number(&mut self) -> VMResult<Number> {
        let top = self.pop_word().chain_err(|| "unable to pop word off the stack")?;
        Ok(Number::from_bits(top))
    }

    fn add(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a + b).chain_err(|| "unable to push value to the stack")?;
        Ok(())
    }

    fn sub(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a - b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn mul(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a * b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn div(&mut self) -> VMResult<()> {
        let b = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        let a = self.pop_number().chain_err(|| "unable to pop word off the stack")?;
        self.push_number(a / b).chain_err(|| "unable to push to stack")?;
        Ok(())
    }

    fn jmp(&mut self, addr: Address) -> VMResult<()> {
        self.pc = addr;
        Ok(())
    }

    fn read_word(&mut self) -> VMResult<Word> {
        // Build a Word from single bytes
        let mut res: Word = 0;
        for _ in 0..8 {
            res <<= 8;
            self.advance_pc();
            let current_byte = self.current_byte().chain_err(|| "unable to read current byte")?;
            res |= current_byte as Word;
        }

        Ok(res)
    }

    fn read_small_word(&mut self) -> VMResult<SmallWord> {
        // Build a Word from single bytes
        let mut res: SmallWord = 0;
        for _ in 0..4 {
            res <<= 8;
            self.advance_pc();
            let current_byte = self.current_byte().chain_err(|| "unable to read current byte")?;
            res |= current_byte as SmallWord;
        }

        Ok(res)
    }

    fn read_tiny_word(&mut self) -> VMResult<TinyWord> {
        // Build a Word from single bytes
        let mut res: TinyWord = 0;
        for _ in 0..2 {
            res <<= 8;
            self.advance_pc();
            let current_byte = self.current_byte().chain_err(|| "unable to read current byte")?;
            res |= current_byte as TinyWord;
        }

        Ok(res)
    }

    fn advance_pc(&mut self) {
        self.pc += 1;
    }

    fn current_byte(&mut self) -> VMResult<Byte> {
        if self.pc < self.image.len() {
            Ok(self.image[self.pc])
        } else {
            bail!("program counter out of bounds");
        }
    }

    fn peek_word(&mut self) -> VMResult<Word> {
        if self.stack_ptr < self.stack.len() {
            Ok(self.stack[self.stack_ptr])
        } else {
            bail!("stack pointer out of bounds");
        }
    }

    fn peek_number(&mut self) -> VMResult<Number> {
        let top = self.peek_word().chain_err(|| "unable to peek for word")?;
        Ok(Number::from_bits(top))
    }
}
<|endoftext|>


<commit_before>extern crate skim;
use skim::{Skim, SkimOptionsBuilder};
use std::default::Default;
use std::io::Cursor;

pub fn main() {
    let options = SkimOptionsBuilder::default()
        .height(Some("50%"))
        .multi(true)
        .build()
        .unwrap();

    //==================================================
    // first run
    let input = "aaaaa\nbbbb\nccc".to_string();

    let selected_items = Skim::run_with(&options, Some(Box::new(Cursor::new(input))))
        .map(|out| out.selected_items)
        .unwrap_or_else(|| Vec::new());

    for item in selected_items.iter() {
        print!("{}: {}{}", item.get_index(), item.get_output_text(), "\n");
    }

    //==================================================
    // second run
    let input = "11111\n22222\n333333333".to_string();

    let selected_items = Skim::run_with(&options, Some(Box::new(Cursor::new(input))))
        .map(|out| out.selected_items)
        .unwrap_or_else(|| Vec::new());

    for item in selected_items.iter() {
        print!("{}: {}{}", item.get_index(), item.get_output_text(), "\n");
    }
}
<commit_msg>option_builder.rs: remove extraneous line.<commit_after>extern crate skim;
use skim::{Skim, SkimOptionsBuilder};
use std::io::Cursor;

pub fn main() {
    let options = SkimOptionsBuilder::default()
        .height(Some("50%"))
        .multi(true)
        .build()
        .unwrap();

    //==================================================
    // first run
    let input = "aaaaa\nbbbb\nccc".to_string();

    let selected_items = Skim::run_with(&options, Some(Box::new(Cursor::new(input))))
        .map(|out| out.selected_items)
        .unwrap_or_else(|| Vec::new());

    for item in selected_items.iter() {
        print!("{}: {}{}", item.get_index(), item.get_output_text(), "\n");
    }

    //==================================================
    // second run
    let input = "11111\n22222\n333333333".to_string();

    let selected_items = Skim::run_with(&options, Some(Box::new(Cursor::new(input))))
        .map(|out| out.selected_items)
        .unwrap_or_else(|| Vec::new());

    for item in selected_items.iter() {
        print!("{}: {}{}", item.get_index(), item.get_output_text(), "\n");
    }
}
<|endoftext|>


<commit_before>extern crate tera;

use super::serde::Serialize;
use super::TemplateInfo;

use self::tera::Tera;

static mut TERA: Option<Tera> = None;

pub const EXT: &'static str = "tera";

// This function must be called a SINGLE TIME from A SINGLE THREAD for safety to
// hold here and in `render`.
pub unsafe fn register(templates: &[(&str, &TemplateInfo)]) -> bool {
    if TERA.is_some() {
        error_!("Internal error: reregistering Tera!");
        return false;
    }

    let mut tera = Tera::default();
    let ext = [".html.tera", ".htm.tera", ".xml.tera", ".html", ".htm", ".xml"];
    tera.autoescape_on(ext.to_vec());

    // Collect into a tuple of (name, path) for Tera.
    let tera_templates = templates.iter()
        .map(|&(name, info)| (&info.full_path, Some(name)))
        .collect::<Vec<_>>();

    // Finally try to tell Tera about all of the templates.
    let mut success = true;
    if let Err(e) = tera.add_template_files(tera_templates) {
        error_!("Failed to initialize Tera templates: {:?}", e);
        success = false;
    }

    TERA = Some(tera);
    success
}

pub fn render<T>(name: &str, _: &TemplateInfo, context: &T) -> Option<String>
    where T: Serialize
{
    let tera = match unsafe { TERA.as_ref() } {
        Some(tera) => tera,
        None => {
            error_!("Internal error: `render` called before Tera init.");
            return None;
        }
    };

    if tera.get_template(name).is_err() {
        error_!("Tera template '{}' does not exist.", name);
        return None;
    };

    match tera.value_render(name, context) {
        Ok(string) => Some(string),
        Err(e) => {
            error_!("Error rendering Tera template '{}': {}", name, e);
            None
        }
    }
}
<commit_msg>Iterate through Tera error chain for better errors.<commit_after>extern crate tera;

use super::serde::Serialize;
use super::TemplateInfo;

use self::tera::Tera;

static mut TERA: Option<Tera> = None;

pub const EXT: &'static str = "tera";

// This function must be called a SINGLE TIME from A SINGLE THREAD for safety to
// hold here and in `render`.
pub unsafe fn register(templates: &[(&str, &TemplateInfo)]) -> bool {
    if TERA.is_some() {
        error_!("Internal error: reregistering Tera!");
        return false;
    }

    let mut tera = Tera::default();
    let ext = [".html.tera", ".htm.tera", ".xml.tera", ".html", ".htm", ".xml"];
    tera.autoescape_on(ext.to_vec());

    // Collect into a tuple of (name, path) for Tera.
    let tera_templates = templates.iter()
        .map(|&(name, info)| (&info.full_path, Some(name)))
        .collect::<Vec<_>>();

    // Finally try to tell Tera about all of the templates.
    let mut success = true;
    if let Err(e) = tera.add_template_files(tera_templates) {
        error_!("Failed to initialize Tera templates: {:?}", e);
        success = false;
    }

    TERA = Some(tera);
    success
}

pub fn render<T>(name: &str, _: &TemplateInfo, context: &T) -> Option<String>
    where T: Serialize
{
    let tera = match unsafe { TERA.as_ref() } {
        Some(tera) => tera,
        None => {
            error_!("Internal error: `render` called before Tera init.");
            return None;
        }
    };

    if tera.get_template(name).is_err() {
        error_!("Tera template '{}' does not exist.", name);
        return None;
    };

    match tera.value_render(name, context) {
        Ok(string) => Some(string),
        Err(e) => {
            error_!("Error rendering Tera template '{}'.", name);
            for error in e.iter().skip(1) {
                error_!("{}.", error);
            }

            None
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
extern crate base64;

use base64::*;

fn compare_encode(expected: &str, target: &[u8]) {
    assert_eq!(expected, encode(target));
}

fn compare_decode(expected: &str, target: &str) {
    assert_eq!(expected, String::from_utf8(decode(target).unwrap()).unwrap());
}

fn compare_decode_ws(expected: &str, target: &str) {
    assert_eq!(expected, String::from_utf8(decode_ws(target).unwrap()).unwrap());
}

//-------
//decode

#[test]
fn decode_rfc4648_0() {
    compare_decode("", "");
}

#[test]
fn decode_rfc4648_1() {
    compare_decode("f", "Zg==");
}

#[test]
fn decode_rfc4648_2() {
    compare_decode("fo", "Zm8=");
}

#[test]
fn decode_rfc4648_3() {
    compare_decode("foo", "Zm9v");
}

#[test]
fn decode_rfc4648_4() {
    compare_decode("foob", "Zm9vYg==");
}

#[test]
fn decode_rfc4648_5() {
    compare_decode("fooba", "Zm9vYmE=");
}

#[test]
fn decode_rfc4648_6() {
    compare_decode("foobar", "Zm9vYmFy");
}

//this is a MAY in the rfc
#[test]
fn decode_allow_extra_pad() {
    compare_decode("alice", "YWxpY2U=====");
}

//same
#[test]
fn decode_allow_absurd_pad() {
    compare_decode("alice", "==Y=Wx===pY=2U=====");
}

//TODO like, write a thing to test every ascii val lol
//prolly just yankput the 64 array and a 256 one later
//is there a way to like, not have to write a fn every time
//"hi test harness this should panic 192 times" would be nice
//oh well whatever this is better done by a fuzzer

//strip yr whitespace kids
#[test]
#[should_panic]
fn decode_reject_space() {
    assert!(decode("YWx pY2U=").is_ok());
}

#[test]
#[should_panic]
fn decode_reject_tab() {
    assert!(decode("YWx\tpY2U=").is_ok());
}

#[test]
#[should_panic]
fn decode_reject_nl() {
    assert!(decode("YWx\npY2U=").is_ok());
}

#[test]
#[should_panic]
fn decode_reject_crnl() {
    assert!(decode("YWx\r\npY2U=").is_ok());
}

#[test]
#[should_panic]
fn decode_reject_null() {
    assert!(decode("YWx\0pY2U=").is_ok());
}

//TODO unicode tests
//put in a seperate file so this remains valid ascii

#[test]
fn decode_ws_absurd_whitespace() {
    compare_decode_ws("how could you let this happen",
        "\n aG93I\n\nGNvd\r\nWxkI HlvdSB \tsZXQgdGh\rpcyBo\x0cYXBwZW4 =   ");
}

//-------
//encode

#[test]
fn encode_rfc4648_0() {
    compare_encode("", b"");
}

#[test]
fn encode_rfc4648_1() {
    compare_encode("Zg==", b"f");
}

#[test]
fn encode_rfc4648_2() {
    compare_encode("Zm8=", b"fo");
}

#[test]
fn encode_rfc4648_3() {
    compare_encode("Zm9v", b"foo");
}

#[test]
fn encode_rfc4648_4() {
    compare_encode("Zm9vYg==", b"foob");
}

#[test]
fn encode_rfc4648_5() {
    compare_encode("Zm9vYmE=", b"fooba");
}

#[test]
fn encode_rfc4648_6() {
    compare_encode("Zm9vYmFy", b"foobar");
}

#[test]
fn encode_all_ascii() {
    let mut ascii = Vec::<u8>::with_capacity(128);

    for i in 0..128 {
        ascii.push(i);
    }

    compare_encode("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=", &ascii);
}

#[test]
fn encode_all_bytes() {
    let mut bytes = Vec::<u8>::with_capacity(256);

    for i in 0..255 {
        bytes.push(i);
    }
    bytes.push(255); //bug with "overflowing" ranges?

    compare_encode("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", &bytes);
}

#[test]
fn encode_all_bytes_url() {
    let mut bytes = Vec::<u8>::with_capacity(256);

    for i in 0..255 {
        bytes.push(i);
    }
    bytes.push(255); //bug with "overflowing" ranges?

    assert_eq!("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w==", encode_mode(&bytes, Base64Mode::UrlSafe));
}

#[test]
fn because_we_can() {
    compare_decode("alice", "YWxpY2U=");
    compare_decode("alice", &encode(b"alice"));
    compare_decode("alice", &encode(&decode(&encode(b"alice")).unwrap()));
}
<commit_msg>Add tests for base64 without padding, as well as roundtrip tests for every possible 1, 2, and 3 byte string (encode, then decode) and random byte strings up to length 10.<commit_after>extern crate base64;
extern crate rand;

use rand::Rng;

use base64::*;

fn compare_encode(expected: &str, target: &[u8]) {
    assert_eq!(expected, encode(target));
}

fn compare_decode(expected: &str, target: &str) {
    assert_eq!(expected, String::from_utf8(decode(target).unwrap()).unwrap());
}

fn compare_decode_ws(expected: &str, target: &str) {
    assert_eq!(expected, String::from_utf8(decode_ws(target).unwrap()).unwrap());
}

// generate every possible byte string recursively and test encode/decode roundtrip
fn roundtrip_append_recurse(byte_buf: &mut Vec<u8>, str_buf: &mut String, remaining_bytes: usize) {
    let orig_length = byte_buf.len();
    for b in 0..256 {
        byte_buf.push(b as u8);

        if remaining_bytes > 1 {
            roundtrip_append_recurse(byte_buf, str_buf, remaining_bytes - 1)
        } else {
            encode_mode_buf(&byte_buf, Base64Mode::Standard, str_buf);
            let roundtrip_bytes = decode_mode(&str_buf, Base64Mode::Standard).unwrap();
            assert_eq!(*byte_buf, roundtrip_bytes);

            str_buf.clear();

        }

        byte_buf.truncate(orig_length);
    }
}

// generate every possible byte string recursively and test encode/decode roundtrip with
// padding removed
fn roundtrip_append_recurse_strip_padding(byte_buf: &mut Vec<u8>, str_buf: &mut String,
                                          remaining_bytes: usize) {
    let orig_length = byte_buf.len();
    for b in 0..256 {
        byte_buf.push(b as u8);

        if remaining_bytes > 1 {
            roundtrip_append_recurse_strip_padding(byte_buf, str_buf, remaining_bytes - 1)
        } else {
            encode_mode_buf(&byte_buf, Base64Mode::Standard, str_buf);
            {
                let trimmed = str_buf.trim_right_matches('=');
                let roundtrip_bytes = decode_mode(&trimmed, Base64Mode::Standard).unwrap();
                assert_eq!(*byte_buf, roundtrip_bytes);
            }
            str_buf.clear();
        }

        byte_buf.truncate(orig_length);
    }
}

// generate random contents of the specified length and test encode/decode roundtrip
fn roundtrip_random(byte_buf: &mut Vec<u8>, str_buf: &mut String, byte_len: usize,
                    approx_values_per_byte: u8) {
    let num_rounds = (approx_values_per_byte as u32).pow(byte_len as u32);
    let mut r = rand::weak_rng();

    for _ in 0..num_rounds {
        byte_buf.clear();
        str_buf.clear();
        while byte_buf.len() < byte_len {
            byte_buf.push(r.gen::<u8>());
        }

        encode_mode_buf(&byte_buf, Base64Mode::Standard, str_buf);
        let roundtrip_bytes = decode_mode(&str_buf, Base64Mode::Standard).unwrap();

        assert_eq!(*byte_buf, roundtrip_bytes);
    }
}

// generate random contents of the specified length and test encode/decode roundtrip
fn roundtrip_random_strip_padding(byte_buf: &mut Vec<u8>, str_buf: &mut String, byte_len: usize,
                    approx_values_per_byte: u8) {
    let num_rounds = (approx_values_per_byte as u32).pow(byte_len as u32);
    let mut r = rand::weak_rng();

    for _ in 0..num_rounds {
        byte_buf.clear();
        str_buf.clear();
        while byte_buf.len() < byte_len {
            byte_buf.push(r.gen::<u8>());
        }

        encode_mode_buf(&byte_buf, Base64Mode::Standard, str_buf);
        let trimmed = str_buf.trim_right_matches('=');
        let roundtrip_bytes = decode_mode(&trimmed, Base64Mode::Standard).unwrap();

        assert_eq!(*byte_buf, roundtrip_bytes);
    }
}

//-------
//decode

#[test]
fn decode_rfc4648_0() {
    compare_decode("", "");
}

#[test]
fn decode_rfc4648_1() {
    compare_decode("f", "Zg==");
}

#[test]
fn decode_rfc4648_1_no_padding() {
    compare_decode("f", "Zg");
}

#[test]
fn decode_rfc4648_2() {
    compare_decode("fo", "Zm8=");
}

#[test]
fn decode_rfc4648_2_no_padding() {
    compare_decode("fo", "Zm8");
}

#[test]
fn decode_rfc4648_3() {
    compare_decode("foo", "Zm9v");
}

#[test]
fn decode_rfc4648_4() {
    compare_decode("foob", "Zm9vYg==");
}

#[test]
fn decode_rfc4648_4_no_padding() {
    compare_decode("foob", "Zm9vYg");
}

#[test]
fn decode_rfc4648_5() {
    compare_decode("fooba", "Zm9vYmE=");
}

#[test]
fn decode_rfc4648_5_no_padding() {
    compare_decode("fooba", "Zm9vYmE");
}

#[test]
fn decode_rfc4648_6() {
    compare_decode("foobar", "Zm9vYmFy");
}

//this is a MAY in the rfc
#[test]
fn decode_allow_extra_pad() {
    compare_decode("alice", "YWxpY2U=====");
}

//same
#[test]
fn decode_allow_absurd_pad() {
    compare_decode("alice", "==Y=Wx===pY=2U=====");
}

#[test]
fn roundtrip_random_short() {
    let mut byte_buf: Vec<u8> = Vec::new();
    let mut str_buf = String::new();

    for input_len in 0..10 {
        roundtrip_random(&mut byte_buf, &mut str_buf, input_len, 4);
    }
}

#[test]
fn roundtrip_random_short_no_padding() {
    let mut byte_buf: Vec<u8> = Vec::new();
    let mut str_buf = String::new();

    for input_len in 0..10 {
        roundtrip_random_strip_padding(&mut byte_buf, &mut str_buf, input_len, 4);
    }
}

#[test]
fn roundtrip_all_1_byte() {
    let mut byte_buf: Vec<u8> = Vec::new();
    let mut str_buf = String::new();
    roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 1);
}

#[test]
fn roundtrip_all_1_byte_no_padding() {
    let mut byte_buf: Vec<u8> = Vec::new();
    let mut str_buf = String::new();
    roundtrip_append_recurse_strip_padding(&mut byte_buf, &mut str_buf, 1);
}

#[test]
fn roundtrip_all_2_byte() {
    let mut byte_buf: Vec<u8> = Vec::new();
    let mut str_buf = String::new();
    roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 2);
}

#[test]
fn roundtrip_all_2_byte_no_padding() {
    let mut byte_buf: Vec<u8> = Vec::new();
    let mut str_buf = String::new();
    roundtrip_append_recurse_strip_padding(&mut byte_buf, &mut str_buf, 2);
}

#[test]
fn roundtrip_all_3_byte() {
    let mut byte_buf: Vec<u8> = Vec::new();
    let mut str_buf = String::new();
    roundtrip_append_recurse(&mut byte_buf, &mut str_buf, 3);
}

#[test]
fn roundtrip_random_4_byte() {
    let mut byte_buf: Vec<u8> = Vec::new();
    let mut str_buf = String::new();

    roundtrip_random(&mut byte_buf, &mut str_buf, 4, 48);
}

//TODO like, write a thing to test every ascii val lol
//prolly just yankput the 64 array and a 256 one later
//is there a way to like, not have to write a fn every time
//"hi test harness this should panic 192 times" would be nice
//oh well whatever this is better done by a fuzzer

//strip yr whitespace kids
#[test]
#[should_panic]
fn decode_reject_space() {
    assert!(decode("YWx pY2U=").is_ok());
}

#[test]
#[should_panic]
fn decode_reject_tab() {
    assert!(decode("YWx\tpY2U=").is_ok());
}

#[test]
#[should_panic]
fn decode_reject_nl() {
    assert!(decode("YWx\npY2U=").is_ok());
}

#[test]
#[should_panic]
fn decode_reject_crnl() {
    assert!(decode("YWx\r\npY2U=").is_ok());
}

#[test]
#[should_panic]
fn decode_reject_null() {
    assert!(decode("YWx\0pY2U=").is_ok());
}

//TODO unicode tests
//put in a seperate file so this remains valid ascii

#[test]
fn decode_ws_absurd_whitespace() {
    compare_decode_ws("how could you let this happen",
        "\n aG93I\n\nGNvd\r\nWxkI HlvdSB \tsZXQgdGh\rpcyBo\x0cYXBwZW4 =   ");
}

//-------
//encode

#[test]
fn encode_rfc4648_0() {
    compare_encode("", b"");
}

#[test]
fn encode_rfc4648_1() {
    compare_encode("Zg==", b"f");
}

#[test]
fn encode_rfc4648_2() {
    compare_encode("Zm8=", b"fo");
}

#[test]
fn encode_rfc4648_3() {
    compare_encode("Zm9v", b"foo");
}

#[test]
fn encode_rfc4648_4() {
    compare_encode("Zm9vYg==", b"foob");
}

#[test]
fn encode_rfc4648_5() {
    compare_encode("Zm9vYmE=", b"fooba");
}

#[test]
fn encode_rfc4648_6() {
    compare_encode("Zm9vYmFy", b"foobar");
}

#[test]
fn encode_all_ascii() {
    let mut ascii = Vec::<u8>::with_capacity(128);

    for i in 0..128 {
        ascii.push(i);
    }

    compare_encode("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=", &ascii);
}

#[test]
fn encode_all_bytes() {
    let mut bytes = Vec::<u8>::with_capacity(256);

    for i in 0..255 {
        bytes.push(i);
    }
    bytes.push(255); //bug with "overflowing" ranges?

    compare_encode("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", &bytes);
}

#[test]
fn encode_all_bytes_url() {
    let mut bytes = Vec::<u8>::with_capacity(256);

    for i in 0..255 {
        bytes.push(i);
    }
    bytes.push(255); //bug with "overflowing" ranges?

    assert_eq!("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w==", encode_mode(&bytes, Base64Mode::UrlSafe));
}

#[test]
fn because_we_can() {
    compare_decode("alice", "YWxpY2U=");
    compare_decode("alice", &encode(b"alice"));
    compare_decode("alice", &encode(&decode(&encode(b"alice")).unwrap()));
}
<|endoftext|>


<commit_before>use std::{cmp, fmt};

pub struct Clock {
    hours: u8,
    minutes: u8,
}

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        unimplemented!(
            "Construct a new Clock from {} hours and {} minutes",
            hours,
            minutes
        );
    }

    pub fn add_minutes(self, minutes: i32) -> Self {
        unimplemented!("Add {} minutes to existing Clock time", minutes);
    }

    pub fn to_string(&self) -> String {
        unimplemented!("Return String representation of a Clock");
    }
}

impl fmt::Debug for Clock {
    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!("Return debug representation of a Clock");
    }
}

impl cmp::PartialEq for Clock {
    fn eq(&self, _other: &Clock) -> bool {
        unimplemented!("Implement comparison between two Clocks");
    }
}
<commit_msg>clock: Removed fields from Clock struct<commit_after>use std::{cmp, fmt};

pub struct Clock {
}

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        unimplemented!(
            "Construct a new Clock from {} hours and {} minutes",
            hours,
            minutes
        );
    }

    pub fn add_minutes(self, minutes: i32) -> Self {
        unimplemented!("Add {} minutes to existing Clock time", minutes);
    }

    pub fn to_string(&self) -> String {
        unimplemented!("Return String representation of a Clock");
    }
}

impl fmt::Debug for Clock {
    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!("Return debug representation of a Clock");
    }
}

impl cmp::PartialEq for Clock {
    fn eq(&self, _other: &Clock) -> bool {
        unimplemented!("Implement comparison between two Clocks");
    }
}
<|endoftext|>


<commit_before>//! `ra_hir_expand` deals with macro expansion.
//!
//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
//! tree originates not from the text of some `FileId`, but from some macro
//! expansion.

pub mod db;
pub mod ast_id_map;
pub mod either;
pub mod name;
pub mod hygiene;
pub mod diagnostics;
pub mod builtin_macro;
pub mod quote;

use std::hash::{Hash, Hasher};
use std::sync::Arc;

use ra_db::{salsa, CrateId, FileId};
use ra_syntax::{
    ast::{self, AstNode},
    SyntaxNode, TextRange, TextUnit,
};

use crate::ast_id_map::FileAstId;
use crate::builtin_macro::BuiltinExpander;

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    FileId(FileId),
    MacroFile(MacroFile),
}

impl From<FileId> for HirFileId {
    fn from(id: FileId) -> Self {
        HirFileId(HirFileIdRepr::FileId(id))
    }
}

impl From<MacroFile> for HirFileId {
    fn from(id: MacroFile) -> Self {
        HirFileId(HirFileIdRepr::MacroFile(id))
    }
}

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::FileId(file_id) => file_id,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc = db.lookup_intern_macro(macro_file.macro_call_id);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// Return expansion information if it is a macro-expansion file
    pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
        match self.0 {
            HirFileIdRepr::FileId(_) => None,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);

                let arg_start = loc.ast_id.to_node(db).token_tree()?.syntax().text_range().start();
                let def_start =
                    loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start();

                let macro_def = db.macro_def(loc.def)?;
                let shift = macro_def.0.shift();
                let exp_map = db.parse_macro(macro_file)?.1;
                let macro_arg = db.macro_arg(macro_file.macro_call_id)?;

                let arg_start = (loc.ast_id.file_id, arg_start);
                let def_start = (loc.def.ast_id.file_id, def_start);

                Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map, shift })
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFile {
    macro_call_id: MacroCallId,
    macro_file_kind: MacroFileKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroFileKind {
    Items,
    Expr,
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl salsa::InternKey for MacroCallId {
    fn from_intern_id(v: salsa::InternId) -> Self {
        MacroCallId(v)
    }
    fn as_intern_id(&self) -> salsa::InternId {
        self.0
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
    pub krate: CrateId,
    pub ast_id: AstId<ast::MacroCall>,
    pub kind: MacroDefKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroDefKind {
    Declarative,
    BuiltIn(BuiltinExpander),
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub def: MacroDefId,
    pub ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub fn as_file(self, kind: MacroFileKind) -> HirFileId {
        let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
        macro_file.into()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// ExpansionInfo mainly describes how to map text range between src and expanded macro
pub struct ExpansionInfo {
    pub(crate) arg_start: (HirFileId, TextUnit),
    pub(crate) def_start: (HirFileId, TextUnit),
    pub(crate) shift: u32,

    pub(crate) macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
    pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
    pub(crate) exp_map: Arc<mbe::RevTokenMap>,
}

impl ExpansionInfo {
    pub fn translate_offset(&self, offset: TextUnit) -> Option<TextUnit> {
        let offset = offset.checked_sub(self.arg_start.1)?;
        let token_id = self.macro_arg.1.token_by_offset(offset)?;
        let token_id = tt::TokenId(token_id.0 + self.shift);

        let (r, _) = self.exp_map.ranges.iter().find(|(_, tid)| *tid == token_id)?;
        Some(r.start())
    }

    pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> {
        let token_id = look_in_rev_map(&self.exp_map, from)?;

        let (token_map, (file_id, start_offset), token_id) = if token_id.0 >= self.shift {
            (&self.macro_arg.1, self.arg_start, tt::TokenId(token_id.0 - self.shift).into())
        } else {
            (&self.macro_def.1, self.def_start, token_id)
        };

        let range = token_map.relative_range_of(token_id)?;

        return Some((file_id, range + start_offset));

        fn look_in_rev_map(exp_map: &mbe::RevTokenMap, from: TextRange) -> Option<tt::TokenId> {
            exp_map.ranges.iter().find(|&it| it.0.is_subrange(&from)).map(|it| it.1)
        }
    }
}

/// `AstId` points to an AST node in any file.
///
/// It is stable across reparses, and can be used as salsa key/value.
// FIXME: isn't this just a `Source<FileAstId<N>>` ?
#[derive(Debug)]
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> Clone for AstId<N> {
    fn clone(&self) -> AstId<N> {
        *self
    }
}
impl<N: AstNode> Copy for AstId<N> {}

impl<N: AstNode> PartialEq for AstId<N> {
    fn eq(&self, other: &Self) -> bool {
        (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
    }
}
impl<N: AstNode> Eq for AstId<N> {}
impl<N: AstNode> Hash for AstId<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        (self.file_id, self.file_ast_id).hash(hasher);
    }
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }

    pub fn file_id(&self) -> HirFileId {
        self.file_id
    }

    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
        let root = db.parse_or_expand(self.file_id).unwrap();
        db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
    }
}

/// FIXME: https://github.com/matklad/with ?
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct Source<T> {
    pub file_id: HirFileId,
    // FIXME: this stores all kind of things, not only `ast`.
    // There should be a better name...
    pub ast: T,
}

impl<T> Source<T> {
    pub fn new(file_id: HirFileId, ast: T) -> Source<T> {
        Source { file_id, ast }
    }

    // Similarly, naming here is stupid...
    pub fn with_ast<U>(&self, ast: U) -> Source<U> {
        Source::new(self.file_id, ast)
    }

    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source::new(self.file_id, f(self.ast))
    }
    pub fn as_ref(&self) -> Source<&T> {
        self.with_ast(&self.ast)
    }
    pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
        db.parse_or_expand(self.file_id).expect("source created from invalid file")
    }
}
<commit_msg>Don't store shift redundantly<commit_after>//! `ra_hir_expand` deals with macro expansion.
//!
//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
//! tree originates not from the text of some `FileId`, but from some macro
//! expansion.

pub mod db;
pub mod ast_id_map;
pub mod either;
pub mod name;
pub mod hygiene;
pub mod diagnostics;
pub mod builtin_macro;
pub mod quote;

use std::hash::{Hash, Hasher};
use std::sync::Arc;

use ra_db::{salsa, CrateId, FileId};
use ra_syntax::{
    ast::{self, AstNode},
    SyntaxNode, TextRange, TextUnit,
};

use crate::ast_id_map::FileAstId;
use crate::builtin_macro::BuiltinExpander;

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    FileId(FileId),
    MacroFile(MacroFile),
}

impl From<FileId> for HirFileId {
    fn from(id: FileId) -> Self {
        HirFileId(HirFileIdRepr::FileId(id))
    }
}

impl From<MacroFile> for HirFileId {
    fn from(id: MacroFile) -> Self {
        HirFileId(HirFileIdRepr::MacroFile(id))
    }
}

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::FileId(file_id) => file_id,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc = db.lookup_intern_macro(macro_file.macro_call_id);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// Return expansion information if it is a macro-expansion file
    pub fn expansion_info(self, db: &dyn db::AstDatabase) -> Option<ExpansionInfo> {
        match self.0 {
            HirFileIdRepr::FileId(_) => None,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);

                let arg_start = loc.ast_id.to_node(db).token_tree()?.syntax().text_range().start();
                let def_start =
                    loc.def.ast_id.to_node(db).token_tree()?.syntax().text_range().start();

                let macro_def = db.macro_def(loc.def)?;
                let exp_map = db.parse_macro(macro_file)?.1;
                let macro_arg = db.macro_arg(macro_file.macro_call_id)?;

                let arg_start = (loc.ast_id.file_id, arg_start);
                let def_start = (loc.def.ast_id.file_id, def_start);

                Some(ExpansionInfo { arg_start, def_start, macro_arg, macro_def, exp_map })
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFile {
    macro_call_id: MacroCallId,
    macro_file_kind: MacroFileKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroFileKind {
    Items,
    Expr,
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl salsa::InternKey for MacroCallId {
    fn from_intern_id(v: salsa::InternId) -> Self {
        MacroCallId(v)
    }
    fn as_intern_id(&self) -> salsa::InternId {
        self.0
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
    pub krate: CrateId,
    pub ast_id: AstId<ast::MacroCall>,
    pub kind: MacroDefKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroDefKind {
    Declarative,
    BuiltIn(BuiltinExpander),
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub def: MacroDefId,
    pub ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub fn as_file(self, kind: MacroFileKind) -> HirFileId {
        let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
        macro_file.into()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// ExpansionInfo mainly describes how to map text range between src and expanded macro
pub struct ExpansionInfo {
    pub(crate) arg_start: (HirFileId, TextUnit),
    pub(crate) def_start: (HirFileId, TextUnit),

    pub(crate) macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
    pub(crate) macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
    pub(crate) exp_map: Arc<mbe::RevTokenMap>,
}

impl ExpansionInfo {
    pub fn translate_offset(&self, offset: TextUnit) -> Option<TextUnit> {
        let offset = offset.checked_sub(self.arg_start.1)?;
        let token_id = self.macro_arg.1.token_by_offset(offset)?;
        let token_id = tt::TokenId(token_id.0 + self.macro_def.0.shift());

        let (r, _) = self.exp_map.ranges.iter().find(|(_, tid)| *tid == token_id)?;
        Some(r.start())
    }

    pub fn find_range(&self, from: TextRange) -> Option<(HirFileId, TextRange)> {
        let token_id = look_in_rev_map(&self.exp_map, from)?;

        let shift = self.macro_def.0.shift();
        let (token_map, (file_id, start_offset), token_id) = if token_id.0 >= shift {
            (&self.macro_arg.1, self.arg_start, tt::TokenId(token_id.0 - shift).into())
        } else {
            (&self.macro_def.1, self.def_start, token_id)
        };

        let range = token_map.relative_range_of(token_id)?;

        return Some((file_id, range + start_offset));

        fn look_in_rev_map(exp_map: &mbe::RevTokenMap, from: TextRange) -> Option<tt::TokenId> {
            exp_map.ranges.iter().find(|&it| it.0.is_subrange(&from)).map(|it| it.1)
        }
    }
}

/// `AstId` points to an AST node in any file.
///
/// It is stable across reparses, and can be used as salsa key/value.
// FIXME: isn't this just a `Source<FileAstId<N>>` ?
#[derive(Debug)]
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> Clone for AstId<N> {
    fn clone(&self) -> AstId<N> {
        *self
    }
}
impl<N: AstNode> Copy for AstId<N> {}

impl<N: AstNode> PartialEq for AstId<N> {
    fn eq(&self, other: &Self) -> bool {
        (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
    }
}
impl<N: AstNode> Eq for AstId<N> {}
impl<N: AstNode> Hash for AstId<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        (self.file_id, self.file_ast_id).hash(hasher);
    }
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }

    pub fn file_id(&self) -> HirFileId {
        self.file_id
    }

    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
        let root = db.parse_or_expand(self.file_id).unwrap();
        db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
    }
}

/// FIXME: https://github.com/matklad/with ?
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct Source<T> {
    pub file_id: HirFileId,
    // FIXME: this stores all kind of things, not only `ast`.
    // There should be a better name...
    pub ast: T,
}

impl<T> Source<T> {
    pub fn new(file_id: HirFileId, ast: T) -> Source<T> {
        Source { file_id, ast }
    }

    // Similarly, naming here is stupid...
    pub fn with_ast<U>(&self, ast: U) -> Source<U> {
        Source::new(self.file_id, ast)
    }

    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source::new(self.file_id, f(self.ast))
    }
    pub fn as_ref(&self) -> Source<&T> {
        self.with_ast(&self.ast)
    }
    pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
        db.parse_or_expand(self.file_id).expect("source created from invalid file")
    }
}
<|endoftext|>


<commit_before>use std::{
    sync::mpsc::{channel, Receiver, Sender},
};

use pathfinder_color::ColorF;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{vec2f, vec2i};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use pathfinder_resources::embedded::EmbeddedResourceLoader;
use surfman::{
    Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion,
};
use surfman::{SurfaceAccess, SurfaceType};
use winit::dpi::LogicalSize;
use winit::{ControlFlow, Event, EventsLoop, WindowBuilder, WindowEvent};

pub use super::native::*;

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {}

/// Concrete implementation of the window shell.
pub struct Shell
where
    A: ShellAdapter,
{
    flip: bool,
    adapter: A,
    update: bool,
    running: bool,
    request_receiver: Receiver<ShellRequest>,
    request_sender: Sender<ShellRequest>,
    render_context_2_d: RenderContext2D,
    window_builder: WindowBuilder,
    mouse_pos: (f64, f64),
}

// unsafe impl HasRawWindowHandle for Shell
// where
//     A: ShellAdapter,
// {
//     fn raw_window_handle(&self) -> RawWindowHandle {
//         // let handle = WebHandle {
//         //     id: 0,
//         //     ..WebHandle::empty()
//         // };

//         // RawWindowHandle::N
//     }
// }

impl Shell
where
    A: ShellAdapter,
{
    /// Gets if the shell is running.
    pub fn running(&self) -> bool {
        self.running
    }

    /// Gets a a new sender to send request to the window shell.
    pub fn request_sender(&self) -> Sender<ShellRequest> {
        self.request_sender.clone()
    }

    /// Sets running.
    pub fn set_running(&mut self, running: bool) {
        self.running = running;
    }

    /// Get if the shell should be updated.
    pub fn update(&self) -> bool {
        self.update
    }

    /// Sets update.
    pub fn set_update(&mut self, update: bool) {
        self.update = update;
    }

    /// Sets the background color of the window.
    pub fn set_background_color(&mut self, red: u8, green: u8, blue: u8) {}

    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render ctx 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    pub fn flip(&mut self) {
        self.flip = false;
    }

    pub fn run(mut self) {
        // Open a window.
        let mut event_loop = EventsLoop::new();
        let size = self
            .window_builder
            .window
            .dimensions
            .unwrap_or(LogicalSize::new(100.0, 100.0));

        let mut render = true;

        let logical_size = LogicalSize::new(size.width as f64, size.height as f64);

        let window = self.window_builder.clone().build(&event_loop).unwrap();
        window.show();

        // Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
        // GPU.
        let connection = Connection::from_winit_window(&window).unwrap();
        let native_widget = connection
            .create_native_widget_from_winit_window(&window)
            .unwrap();
        let adapter = connection.create_low_power_adapter().unwrap();
        let mut device = connection.create_device(&adapter).unwrap();

        // Request an OpenGL 3.x context. Pathfinder requires this.
        let context_attributes = ContextAttributes {
            version: SurfmanGLVersion::new(3, 0),
            flags: ContextAttributeFlags::ALPHA,
        };
        let context_descriptor = device
            .create_context_descriptor(&context_attributes)
            .unwrap();

        // Make the OpenGL context via `surfman`, and load OpenGL functions.
        let surface_type = SurfaceType::Widget { native_widget };
        let mut context = device.create_context(&context_descriptor).unwrap();
        let surface = device
            .create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
            .unwrap();
        device
            .bind_surface_to_context(&mut context, surface)
            .unwrap();
        device.make_context_current(&context).unwrap();
        gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));

        // Get the real size of the window, taking HiDPI into account.
        let hidpi_factor = window.get_current_monitor().get_hidpi_factor();
        let physical_size = logical_size.to_physical(hidpi_factor);
        let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);

        // Create a Pathfinder GL device.
        let default_framebuffer = device
            .context_surface_info(&context)
            .unwrap()
            .unwrap()
            .framebuffer_object;
        let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);

        // Create a Pathfinder renderer.
        let mut renderer = Renderer::new(
            pathfinder_device,
            &EmbeddedResourceLoader::new(),
            DestFramebuffer::full_window(framebuffer_size),
            RendererOptions {
                background_color: Some(ColorF::white()),
                ..RendererOptions::default()
            },
        );

        self.render_context_2_d =
            RenderContext2D::new_ex((size.width as f64, size.height as f64), renderer);

        // Wait for a keypress.
        event_loop.run_forever(|evt| match evt {
            Event::WindowEvent {
                event: WindowEvent::Resized(s),
                ..
            } => {
                self.adapter.resize(s.width, s.height);
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::CloseRequested,
                ..
            } => {
                self.adapter.quit_event();
                ControlFlow::Break
            }
            Event::WindowEvent {
                event: WindowEvent::KeyboardInput { input, .. },
                // todo: implement
                ..
            } => ControlFlow::Continue,
            Event::WindowEvent {
                event: WindowEvent::MouseInput { state, button, .. },
                ..
            } => {
                let button = {
                    match button {
                        winit::MouseButton::Left => MouseButton::Left,
                        winit::MouseButton::Right => MouseButton::Right,
                        winit::MouseButton::Middle => MouseButton::Middle,
                        winit::MouseButton::Other(_) => MouseButton::Left,
                    }
                };

                let state = {
                    match state {
                        winit::ElementState::Pressed => ButtonState::Down,
                        winit::ElementState::Released => ButtonState::Up,
                    }
                };

                let mouse_pos = self.mouse_pos;

                self.adapter.mouse_event(MouseEvent {
                    x: mouse_pos.0,
                    y: mouse_pos.1,
                    button,
                    state,
                });
                render = true;
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::MouseWheel { delta, .. },
                ..
            } => {
                match delta {
                    winit::MouseScrollDelta::LineDelta(_, _) => {}
                    winit::MouseScrollDelta::PixelDelta(p) => {
                        self.adapter.scroll(p.x, p.y);
                    }
                }
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::CursorMoved { position, .. },
                ..
            } => {
                self.mouse_pos = (position.x, position.y);
                self.adapter.mouse(position.x, position.y);
                render = true;
                ControlFlow::Continue
            }
            // | Event::WindowEvent {
            //     event: WindowEvent::KeyboardInput { .. },
            //     ..
            // } => ControlFlow::Break,
            _ => {
                // if let Some(updater) = &mut self.updater {
                //     updater.update();
                // }
                // todo: shell context
                self.adapter.run(&mut self.render_context_2_d);
                self.set_update(true);
                self.flip();
                // self.drain_events();

                if render {
                    // Present the rendered canvas via `surfman`.
                    let mut surface = device
                        .unbind_surface_from_context(&mut context)
                        .unwrap()
                        .unwrap();
                    device.present_surface(&mut context, &mut surface).unwrap();
                    device
                        .bind_surface_to_context(&mut context, surface)
                        .unwrap();
                    render = false;
                }

                ControlFlow::Continue
            }
        });

        // Clean up.
        drop(device.destroy_context(&mut context));
    }
}

/// Constructs the window shell
pub struct ShellBuilder
where
    A: ShellAdapter,
{
    title: String,

    borderless: bool,

    resizeable: bool,

    always_on_top: bool,

    bounds: Rectangle,

    adapter: A,
}

impl ShellBuilder
where
    A: ShellAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        ShellBuilder {
            adapter,
            title: String::default(),
            borderless: false,
            resizeable: false,
            always_on_top: false,
            bounds: Rectangle::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets borderless.
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Does nothing on web.
    pub fn always_on_top(mut self, always_on_top: bool) -> Self {
        self.always_on_top = always_on_top;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rectangle>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(self) -> Shell {
        let (request_sender, request_receiver) = channel();

        // Calculate the right logical size of the window.
        // let event_loop = EventLoop::new();
        let size = (self.bounds.width(), self.bounds.height());

        let logical_size = LogicalSize::new(size.0, size.1);
        // Open a window.
        let window_builder = WindowBuilder::new()
            .with_dimensions(logical_size)
            .with_title(self.title)
            .with_resizable(self.resizeable)
            .with_always_on_top(self.always_on_top)
            .with_decorations(!self.borderless);

        Shell {
            flip: false,
            update: true,
            running: true,
            request_receiver,
            request_sender,
            render_context_2_d: RenderContext2D::new(size.0, size.1),
            adapter: self.adapter,
            window_builder,
            mouse_pos: (0.0, 0.0),
        }
    }
}
<commit_msg>Improve sufrman shell.<commit_after>use std::sync::mpsc::{channel, Receiver, Sender};

use pathfinder_color::ColorF;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{vec2f, vec2i};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use pathfinder_resources::embedded::EmbeddedResourceLoader;
use surfman::{
    Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion,
};
use surfman::{SurfaceAccess, SurfaceType};
use winit::dpi::LogicalSize;
use winit::{ControlFlow, Event, EventsLoop, WindowBuilder, WindowEvent};

pub use super::native::*;

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {}

/// Concrete implementation of the window shell.
pub struct Shell
where
    A: ShellAdapter,
{
    adapter: A,
    update: bool,
    render: bool,
    running: bool,
    request_receiver: Receiver<ShellRequest>,
    request_sender: Sender<ShellRequest>,
    render_context_2_d: RenderContext2D,
    window_builder: WindowBuilder,
    mouse_pos: (f64, f64),
}

// unsafe impl HasRawWindowHandle for Shell
// where
//     A: ShellAdapter,
// {
//     fn raw_window_handle(&self) -> RawWindowHandle {
//         // let handle = WebHandle {
//         //     id: 0,
//         //     ..WebHandle::empty()
//         // };

//         // RawWindowHandle::N
//     }
// }

impl Shell
where
    A: ShellAdapter,
{
    /// Gets if the shell is running.
    pub fn running(&self) -> bool {
        self.running
    }

    /// Gets a a new sender to send request to the window shell.
    pub fn request_sender(&self) -> Sender<ShellRequest> {
        self.request_sender.clone()
    }

    /// Sets running.
    pub fn set_running(&mut self, running: bool) {
        self.running = running;
    }

    /// Get if the shell should be updated.
    pub fn update(&self) -> bool {
        self.update
    }

    /// Sets update.
    pub fn set_update(&mut self, update: bool) {
        self.update = update;
    }

    /// Sets the background color of the window.
    pub fn set_background_color(&mut self, red: u8, green: u8, blue: u8) {}

    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render ctx 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    fn drain_events(&mut self, event: Event) -> ControlFlow {
        match event {
            Event::WindowEvent {
                event: WindowEvent::Resized(s),
                ..
            } => {
                self.adapter.resize(s.width, s.height);
                self.update = true;
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::CloseRequested,
                ..
            } => {
                self.adapter.quit_event();
                ControlFlow::Break
            }
            Event::WindowEvent {
                event: WindowEvent::KeyboardInput { input, .. },
                // todo: implement
                ..
            } => ControlFlow::Continue,
            Event::WindowEvent {
                event: WindowEvent::MouseInput { state, button, .. },
                ..
            } => {
                let button = {
                    match button {
                        winit::MouseButton::Left => MouseButton::Left,
                        winit::MouseButton::Right => MouseButton::Right,
                        winit::MouseButton::Middle => MouseButton::Middle,
                        winit::MouseButton::Other(_) => MouseButton::Left,
                    }
                };

                let state = {
                    match state {
                        winit::ElementState::Pressed => ButtonState::Down,
                        winit::ElementState::Released => ButtonState::Up,
                    }
                };

                let mouse_pos = self.mouse_pos;

                self.adapter.mouse_event(MouseEvent {
                    x: mouse_pos.0,
                    y: mouse_pos.1,
                    button,
                    state,
                });
                self.update = true;
                self.render = true;
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::MouseWheel { delta, .. },
                ..
            } => {
                match delta {
                    winit::MouseScrollDelta::LineDelta(_, _) => {}
                    winit::MouseScrollDelta::PixelDelta(p) => {
                        self.adapter.scroll(p.x, p.y);
                    }
                }
                self.render = true;
                self.update = true;
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::CursorMoved { position, .. },
                ..
            } => {
                self.mouse_pos = (position.x, position.y);
                self.adapter.mouse(position.x, position.y);
                self.update = true;
                self.render = true;
                ControlFlow::Continue
            }
            _ => ControlFlow::Continue,
        }
    }

    pub fn run(mut self) {
        // Open a window.
        let mut event_loop = EventsLoop::new();
        let size = self
            .window_builder
            .window
            .dimensions
            .unwrap_or(LogicalSize::new(100.0, 100.0));

        let logical_size = LogicalSize::new(size.width as f64, size.height as f64);

        let window = self.window_builder.clone().build(&event_loop).unwrap();
        window.show();

        // Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
        // GPU.
        let connection = Connection::from_winit_window(&window).unwrap();
        let native_widget = connection
            .create_native_widget_from_winit_window(&window)
            .unwrap();
        let adapter = connection.create_low_power_adapter().unwrap();
        let mut device = connection.create_device(&adapter).unwrap();

        // Request an OpenGL 3.x context. Pathfinder requires this.
        let context_attributes = ContextAttributes {
            version: SurfmanGLVersion::new(3, 0),
            flags: ContextAttributeFlags::ALPHA,
        };
        let context_descriptor = device
            .create_context_descriptor(&context_attributes)
            .unwrap();

        // Make the OpenGL context via `surfman`, and load OpenGL functions.
        let surface_type = SurfaceType::Widget { native_widget };
        let mut context = device.create_context(&context_descriptor).unwrap();
        let surface = device
            .create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
            .unwrap();
        device
            .bind_surface_to_context(&mut context, surface)
            .unwrap();
        device.make_context_current(&context).unwrap();
        gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));

        // Get the real size of the window, taking HiDPI into account.
        let hidpi_factor = window.get_current_monitor().get_hidpi_factor();
        let physical_size = logical_size.to_physical(hidpi_factor);
        let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);

        // Create a Pathfinder GL device.
        let default_framebuffer = device
            .context_surface_info(&context)
            .unwrap()
            .unwrap()
            .framebuffer_object;
        let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);

        // Create a Pathfinder renderer.
        let mut renderer = Renderer::new(
            pathfinder_device,
            &EmbeddedResourceLoader::new(),
            DestFramebuffer::full_window(framebuffer_size),
            RendererOptions {
                background_color: Some(ColorF::white()),
                ..RendererOptions::default()
            },
        );

        self.render_context_2_d =
            RenderContext2D::new_ex((size.width as f64, size.height as f64), renderer);

        // Wait for a keypress.
        event_loop.run_forever(|evt| {
            let control_flow = self.drain_events(evt);

            if self.update {
                self.adapter.run(&mut self.render_context_2_d);
                self.update = false;
            }

            if self.render {
                // Present the rendered canvas via `surfman`.
                let mut surface = device
                    .unbind_surface_from_context(&mut context)
                    .unwrap()
                    .unwrap();
                device.present_surface(&mut context, &mut surface).unwrap();
                device
                    .bind_surface_to_context(&mut context, surface)
                    .unwrap();
                self.render = false;
            }

            control_flow
        });

        // Clean up.
        drop(device.destroy_context(&mut context));
    }
}

/// Constructs the window shell
pub struct ShellBuilder
where
    A: ShellAdapter,
{
    title: String,

    borderless: bool,

    resizeable: bool,

    always_on_top: bool,

    bounds: Rectangle,

    adapter: A,
}

impl ShellBuilder
where
    A: ShellAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        ShellBuilder {
            adapter,
            title: String::default(),
            borderless: false,
            resizeable: false,
            always_on_top: false,
            bounds: Rectangle::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets borderless.
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Does nothing on web.
    pub fn always_on_top(mut self, always_on_top: bool) -> Self {
        self.always_on_top = always_on_top;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rectangle>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(self) -> Shell {
        let (request_sender, request_receiver) = channel();

        // Calculate the right logical size of the window.
        // let event_loop = EventLoop::new();
        let size = (self.bounds.width(), self.bounds.height());

        let logical_size = LogicalSize::new(size.0, size.1);
        // Open a window.
        let window_builder = WindowBuilder::new()
            .with_dimensions(logical_size)
            .with_title(self.title)
            .with_resizable(self.resizeable)
            .with_always_on_top(self.always_on_top)
            .with_decorations(!self.borderless);

        Shell {
            render: true,
            update: true,
            running: true,
            request_receiver,
            request_sender,
            render_context_2_d: RenderContext2D::new(size.0, size.1),
            adapter: self.adapter,
            window_builder,
            mouse_pos: (0.0, 0.0),
        }
    }
}
<|endoftext|>