<commit_before>extern crate ansi_term;
#[macro_use]
extern crate clap;
extern crate globset;
extern crate ignore;
#[macro_use]
extern crate nom;
extern crate rayon;

// Import helper macros before `parsers`
#[macro_use]
mod helper_parsers;

mod error;
mod file_utils;
mod parsers;
mod transpile;

enum ErrorCode {
    Ok = 0,
    WalkError = 2,
    FileTypeError = 4,
    TranspilationError = 8,
}

fn main() {
    use ansi_term::Colour::{Red, Green};
    use clap::{App, Arg};
    use file_utils::walk_indentex_files;
    use std::path::{Path, PathBuf};
    use std::process;
    use transpile::transpile_file;
    use rayon::prelude::*;
    use std::cmp;

    let m = App::new("indentex")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Transpiler for an indentation-based superset of LaTeX")
        .arg(Arg::with_name("path")
            .help("Path to a single indentex file or a directory (recursively transpile all \
                   indentex files)")
            .index(1)
            .required(true))
        .arg(Arg::with_name("verbose")
            .help("Show transpilation progress")
            .short("v")
            .long("verbose"))
        .get_matches();

    let path = Path::new(m.value_of("path").unwrap());
    let verbose = m.is_present("verbose");

    let mut ret_val = ErrorCode::Ok;

    let batch: Vec<PathBuf> = if path.is_file() {
        vec![path.to_path_buf()]
    } else if path.is_dir() {
        match walk_indentex_files(&path) {
            Ok(b) => b,
            Err(e) => {
                ret_val = ErrorCode::WalkError;
                println!("{}", Red.bold().paint(format!("{}", e)));
                Vec::new()
            }
        }
    } else {
        ret_val = ErrorCode::FileTypeError;
        println!("{}",
                 Red.bold().paint(format!("Error: path '{}' is neither a file nor a directory",
                                          path.display())));
        Vec::new()
    };

    let ret_val_transpilation = batch.par_iter()
        .map(|p| match transpile_file(&p) {
            Ok(_) => {
                if verbose {
                    println!("Transpiling file '{}'... {}",
                             p.display(),
                             Green.paint("ok"));
                }
                return ErrorCode::Ok as i32;
            }
            Err(e) => {
                if verbose {
                    println!("Transpiling file '{}'... {}",
                             p.display(),
                             Red.paint("failed"));
                }
                println!("{}",
                         Red.bold().paint(format!("Could not transpile '{}': {}", p.display(), e)));
                return ErrorCode::TranspilationError as i32;
            }
        })
        .max()
        .unwrap();

    process::exit(cmp::max(ret_val as i32, ret_val_transpilation));
}
<commit_msg>Fix several small issues<commit_after>extern crate ansi_term;
#[macro_use]
extern crate clap;
extern crate globset;
extern crate ignore;
#[macro_use]
extern crate nom;
extern crate rayon;

// Import helper macros before `parsers`
#[macro_use]
mod helper_parsers;

mod error;
mod file_utils;
mod parsers;
mod transpile;

enum ReturnCode {
    Ok = 0,
    WalkError = 2,
    FileTypeError = 4,
    TranspilationError = 8,
}

fn main() {
    use ansi_term::Colour::{Red, Green};
    use clap::{App, Arg};
    use file_utils::walk_indentex_files;
    use rayon::prelude::*;
    use std::cmp;
    use std::path::{Path, PathBuf};
    use std::process;
    use transpile::transpile_file;

    let m = App::new("indentex")
        .version(crate_version!())
        .author(crate_authors!())
        .about("Transpiler for an indentation-based superset of LaTeX")
        .arg(Arg::with_name("path")
            .help("Path to a single indentex file or a directory (recursively transpile all \
                   indentex files)")
            .index(1)
            .required(true))
        .arg(Arg::with_name("verbose")
            .help("Show transpilation progress")
            .short("v")
            .long("verbose"))
        .get_matches();

    let path = Path::new(m.value_of("path").unwrap());
    let verbose = m.is_present("verbose");

    let mut ret_val = ReturnCode::Ok as i32;

    let batch: Vec<PathBuf> = if path.is_file() {
        vec![path.to_path_buf()]
    } else if path.is_dir() {
        match walk_indentex_files(&path) {
            Ok(b) => b,
            Err(e) => {
                ret_val = ReturnCode::WalkError as i32;
                println!("{}", Red.bold().paint(format!("{}", e)));
                Vec::new()
            }
        }
    } else {
        ret_val = ReturnCode::FileTypeError as i32;
        println!("{}",
                 Red.bold().paint(format!("Error: path '{}' is neither a file nor a directory",
                                          path.display())));
        Vec::new()
    };

    let ret_val_transpilation = batch.par_iter()
        .map(|p| match transpile_file(&p) {
            Ok(_) => {
                if verbose {
                    println!("Transpiling file '{}'... {}",
                             p.display(),
                             Green.paint("ok"));
                }
                ReturnCode::Ok
            }
            Err(e) => {
                if verbose {
                    println!("Transpiling file '{}'... {}",
                             p.display(),
                             Red.paint("failed"));
                }
                println!("{}",
                         Red.bold().paint(format!("Could not transpile '{}': {}", p.display(), e)));
                ReturnCode::TranspilationError
            }
        } as i32)
        .max()
        .unwrap_or(ReturnCode::Ok as i32);

    process::exit(cmp::max(ret_val, ret_val_transpilation));
}
<|endoftext|>


<commit_before>use piston::event::*;
use piston::input::Button::Keyboard;
use piston::input::keyboard::Key;
use glutin_window::GlutinWindow as Window;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use game_object::GameObject;

static OPENGL_VERSION: OpenGL = OpenGL::_3_2;
static SIZE: [u32; 2] = [512, 512];
static PADDLE_SIZE: [f64; 2] = [8.0, 32.0];
static PADDLE_ACCEL: f64 = 4000.0;
static PADDLE_FRICTION: f64 = 0.5;
static PADDLE_MAX_SPEED: f64 = 400.0;
static BALL_SIZE: [f64; 2] = [8.0, 8.0];
static BALL_START_MAX_ANGLE: f64 = 60.0;
static BALL_START_SPEED: f64 = 200.0;
static BALL_SPEED_INCREMENT: f64 = 25.0;

struct Pong {
    gl: GlGraphics,
    p1: GameObject,
    p2: GameObject,
    ball: GameObject,
    up: bool,
    down: bool,
    server: Player,
    p1_score: u32,
    p2_score: u32,
}

enum Player {
    Left,
    Right
}

impl Pong {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
        const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

        let objs = [&mut self.p1, &mut self.p2, &mut self.ball];
        self.gl.draw(args.viewport(), |c, gl| {
            clear(BLACK, gl);

            for obj in objs.iter() {
                let rect = [0.0, 0.0, obj.size[0], obj.size[1]];
                let transform = c.transform.trans(obj.pos[0], obj.pos[1])
                    .trans(-obj.size[0] / 2.0, -obj.size[1] / 2.0);
                rectangle(WHITE, rect, transform, gl);
            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        let (ai_up, ai_down) = self.handle_ai_paddle();

        Pong::handle_paddle(&mut self.p1, self.up, self.down, args.dt);
        Pong::handle_paddle(&mut self.p2, ai_up, ai_down, args.dt);
        Pong::handle_game_object(&mut self.p1, args.dt, false);
        Pong::handle_game_object(&mut self.p2, args.dt, false);
        Pong::handle_game_object(&mut self.ball, args.dt, true);
        self.handle_ball();
    }

    fn start(&mut self) {
        self.p1.pos = [self.p1.size[0] / 2.0 + 4.0, (SIZE[1] / 2) as f64];
        self.p2.pos = [SIZE[0] as f64 - self.p2.size[0] / 2.0 - 4.0,
            (SIZE[1] / 2) as f64];

        self.reset();
    }

    fn reset(&mut self) {
        use std::f64::consts::PI;
        use rand;
        use rand::Rng;

        self.ball.pos = [(SIZE[0] / 2) as f64, (SIZE[1] / 2) as f64];

        let mut rng = rand::thread_rng();
        let max_angle = 2.0 * BALL_START_MAX_ANGLE * PI / 180.0;
        let angle = rng.next_f64() * max_angle - max_angle / 2.0;
        self.ball.vel = [
            angle.cos() * BALL_START_SPEED * self.serve_direction(),
            angle.sin() * BALL_START_SPEED
        ];
    }

    fn serve_direction(&mut self) -> f64 {
        match self.server {
            Player::Left => { -1.0 }
            Player::Right => { 1.0 }
        }
    }

    fn key_press(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = true; }
            Key::Down => { self.down = true; }
            _ => {}
        }
    }

    fn key_release(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = false; }
            Key::Down => { self.down = false; }
            _ => {}
        }
    }

    fn handle_game_object(obj: &mut GameObject, dt: f64, bounce: bool) {
        obj.pos[0] += obj.vel[0] * dt;
        obj.pos[1] += obj.vel[1] * dt;

        if obj.pos[1] + obj.size[1] / 2.0 >= SIZE[1] as f64 {
            obj.pos[1] = SIZE[1] as f64 - obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }

        if obj.pos[1] - obj.size[1] / 2.0 <= 0.0f64 {
            obj.pos[1] = obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }
    }

    fn handle_paddle(paddle: &mut GameObject, up: bool, down: bool, dt: f64) {
        if up {
            paddle.vel[1] -= PADDLE_ACCEL * dt;
        } else if down {
            paddle.vel[1] += PADDLE_ACCEL * dt;
        } else {
            let dv = -paddle.vel[1].signum() * PADDLE_ACCEL * dt;

            if dv.abs() >= paddle.vel[1].abs() { paddle.vel[1] = 0.0; }
            else { paddle.vel[1] += dv; }
        }

        if paddle.vel[1] > PADDLE_MAX_SPEED {
            paddle.vel[1] = PADDLE_MAX_SPEED;
        } else if paddle.vel[1] < -PADDLE_MAX_SPEED {
            paddle.vel[1] = -PADDLE_MAX_SPEED;
        }
    }

    fn handle_ai_paddle(&self) -> (bool, bool) {
        let mut ai_up = false;
        let mut ai_down = false;

        if self.ball.vel[0] > 0.0 {
            let t = (self.p2.pos[0] - self.ball.pos[0]) / self.ball.vel[0];
            let target_y = self.ball.pos[1] + self.ball.vel[1] * t;

            if target_y > self.p2.pos[1] { ai_down = true; }
            else if target_y < self.p2.pos[1] { ai_up = true; }
        }

        (ai_up, ai_down)
    }

    fn handle_ball(&mut self) {
        for paddle in [&self.p1, &self.p2].iter() {
            match self.ball.collision_normal(paddle) {
                Some(normal) => {
                    let dot = self.ball.vel[0] * normal[0] +
                        self.ball.vel[1] * normal[1];

                    // reflect ball's velocity off collision normal
                    self.ball.vel = [
                        self.ball.vel[0] - 2.0 * normal[0] * dot,
                        self.ball.vel[1] - 2.0 * normal[1] * dot
                    ];

                    // apply a bit of paddle y velocity to ball
                    if normal[0] != 0.0 {
                        self.ball.vel[1] += paddle.vel[1] * PADDLE_FRICTION;
                    }

                    // increment ball x velocity a bit
                    self.ball.vel[0] += BALL_SPEED_INCREMENT *
                        self.ball.vel[0].signum();

                    Pong::correct_collision(&mut self.ball, paddle, normal);
                }

                None => {}
            }
        }

        if self.ball.pos[0] > SIZE[0] as f64 { self.score(Player::Left); }
        else if self.ball.pos[0] < 0.0 { self.score(Player::Right); }
    }

    fn correct_collision(a: &mut GameObject, b: &GameObject, normal: [f64; 2]) {
        if normal == [1.0, 0.0] {
            a.pos[0] = b.pos[0] + b.size[0] / 2.0 + a.size[0] / 2.0;
        } else if normal == [-1.0, 0.0] {
            a.pos[0] = b.pos[0] - b.size[0] / 2.0 - a.size[0] / 2.0;
        } else if normal == [0.0, 1.0] {
            a.pos[1] = b.pos[1] + b.size[1] / 2.0 + a.size[1] / 2.0;
        } else if normal == [0.0, -1.0] {
            a.pos[1] = b.pos[1] - b.size[1] / 2.0 - a.size[1] / 2.0;
        }
    }

    fn score(&mut self, player: Player) {
        match player {
            Player::Left => {
                self.server = Player::Right;
                self.p1_score += 1;
                println!("Player 1 scored! {}-{}", self.p1_score,
                    self.p2_score);
            }

            Player::Right => {
                self.server = Player::Left;
                self.p2_score += 1;
                println!("Player 2 scored! {}-{}", self.p1_score,
                    self.p2_score);
            }
        }

        self.reset();
    }
}

pub fn play() {

    let window = Window::new(OPENGL_VERSION,
        WindowSettings::new("pong", SIZE)
        .exit_on_esc(true));

    let mut pong = Pong {
        gl: GlGraphics::new(OPENGL_VERSION),
        p1: GameObject { size: PADDLE_SIZE, ..Default::default() },
        p2: GameObject { size: PADDLE_SIZE, ..Default::default() },
        ball: GameObject { size: BALL_SIZE, ..Default::default() },
        up: false,
        down: false,
        server: Player::Left,
        p1_score: 0,
        p2_score: 0,
    };

    pong.start();

    for e in window.events() {
        if let Some(r) = e.render_args() { pong.render(&r); }
        if let Some(u) = e.update_args() { pong.update(&u); }
        if let Some(Keyboard(key)) = e.press_args() { pong.key_press(key); }
        if let Some(Keyboard(key)) = e.release_args() { pong.key_release(key); }
    }
}
<commit_msg>Made object references non-mut for drawing<commit_after>use piston::event::*;
use piston::input::Button::Keyboard;
use piston::input::keyboard::Key;
use glutin_window::GlutinWindow as Window;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use game_object::GameObject;

static OPENGL_VERSION: OpenGL = OpenGL::_3_2;
static SIZE: [u32; 2] = [512, 512];
static PADDLE_SIZE: [f64; 2] = [8.0, 32.0];
static PADDLE_ACCEL: f64 = 4000.0;
static PADDLE_FRICTION: f64 = 0.5;
static PADDLE_MAX_SPEED: f64 = 400.0;
static BALL_SIZE: [f64; 2] = [8.0, 8.0];
static BALL_START_MAX_ANGLE: f64 = 60.0;
static BALL_START_SPEED: f64 = 200.0;
static BALL_SPEED_INCREMENT: f64 = 25.0;

struct Pong {
    gl: GlGraphics,
    p1: GameObject,
    p2: GameObject,
    ball: GameObject,
    up: bool,
    down: bool,
    server: Player,
    p1_score: u32,
    p2_score: u32,
}

enum Player {
    Left,
    Right
}

impl Pong {
    fn render(&mut self, args: &RenderArgs) {
        use graphics::*;

        const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
        const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];

        let objs = [&self.p1, &self.p2, &self.ball];
        self.gl.draw(args.viewport(), |c, gl| {
            clear(BLACK, gl);

            for obj in objs.iter() {
                let rect = [0.0, 0.0, obj.size[0], obj.size[1]];
                let transform = c.transform.trans(obj.pos[0], obj.pos[1])
                    .trans(-obj.size[0] / 2.0, -obj.size[1] / 2.0);
                rectangle(WHITE, rect, transform, gl);
            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        let (ai_up, ai_down) = self.handle_ai_paddle();

        Pong::handle_paddle(&mut self.p1, self.up, self.down, args.dt);
        Pong::handle_paddle(&mut self.p2, ai_up, ai_down, args.dt);
        Pong::handle_game_object(&mut self.p1, args.dt, false);
        Pong::handle_game_object(&mut self.p2, args.dt, false);
        Pong::handle_game_object(&mut self.ball, args.dt, true);
        self.handle_ball();
    }

    fn start(&mut self) {
        self.p1.pos = [self.p1.size[0] / 2.0 + 4.0, (SIZE[1] / 2) as f64];
        self.p2.pos = [SIZE[0] as f64 - self.p2.size[0] / 2.0 - 4.0,
            (SIZE[1] / 2) as f64];

        self.reset();
    }

    fn reset(&mut self) {
        use std::f64::consts::PI;
        use rand;
        use rand::Rng;

        self.ball.pos = [(SIZE[0] / 2) as f64, (SIZE[1] / 2) as f64];

        let mut rng = rand::thread_rng();
        let max_angle = 2.0 * BALL_START_MAX_ANGLE * PI / 180.0;
        let angle = rng.next_f64() * max_angle - max_angle / 2.0;
        self.ball.vel = [
            angle.cos() * BALL_START_SPEED * self.serve_direction(),
            angle.sin() * BALL_START_SPEED
        ];
    }

    fn serve_direction(&mut self) -> f64 {
        match self.server {
            Player::Left => { -1.0 }
            Player::Right => { 1.0 }
        }
    }

    fn key_press(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = true; }
            Key::Down => { self.down = true; }
            _ => {}
        }
    }

    fn key_release(&mut self, key: Key) {
        match key {
            Key::Up => { self.up = false; }
            Key::Down => { self.down = false; }
            _ => {}
        }
    }

    fn handle_game_object(obj: &mut GameObject, dt: f64, bounce: bool) {
        obj.pos[0] += obj.vel[0] * dt;
        obj.pos[1] += obj.vel[1] * dt;

        if obj.pos[1] + obj.size[1] / 2.0 >= SIZE[1] as f64 {
            obj.pos[1] = SIZE[1] as f64 - obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }

        if obj.pos[1] - obj.size[1] / 2.0 <= 0.0f64 {
            obj.pos[1] = obj.size[1] / 2.0;
            if bounce { obj.vel[1] *= -1.0; }
            else { obj.vel[1] = 0.0; }
        }
    }

    fn handle_paddle(paddle: &mut GameObject, up: bool, down: bool, dt: f64) {
        if up {
            paddle.vel[1] -= PADDLE_ACCEL * dt;
        } else if down {
            paddle.vel[1] += PADDLE_ACCEL * dt;
        } else {
            let dv = -paddle.vel[1].signum() * PADDLE_ACCEL * dt;

            if dv.abs() >= paddle.vel[1].abs() { paddle.vel[1] = 0.0; }
            else { paddle.vel[1] += dv; }
        }

        if paddle.vel[1] > PADDLE_MAX_SPEED {
            paddle.vel[1] = PADDLE_MAX_SPEED;
        } else if paddle.vel[1] < -PADDLE_MAX_SPEED {
            paddle.vel[1] = -PADDLE_MAX_SPEED;
        }
    }

    fn handle_ai_paddle(&self) -> (bool, bool) {
        let mut ai_up = false;
        let mut ai_down = false;

        if self.ball.vel[0] > 0.0 {
            let t = (self.p2.pos[0] - self.ball.pos[0]) / self.ball.vel[0];
            let target_y = self.ball.pos[1] + self.ball.vel[1] * t;

            if target_y > self.p2.pos[1] { ai_down = true; }
            else if target_y < self.p2.pos[1] { ai_up = true; }
        }

        (ai_up, ai_down)
    }

    fn handle_ball(&mut self) {
        for paddle in [&self.p1, &self.p2].iter() {
            match self.ball.collision_normal(paddle) {
                Some(normal) => {
                    let dot = self.ball.vel[0] * normal[0] +
                        self.ball.vel[1] * normal[1];

                    // reflect ball's velocity off collision normal
                    self.ball.vel = [
                        self.ball.vel[0] - 2.0 * normal[0] * dot,
                        self.ball.vel[1] - 2.0 * normal[1] * dot
                    ];

                    // apply a bit of paddle y velocity to ball
                    if normal[0] != 0.0 {
                        self.ball.vel[1] += paddle.vel[1] * PADDLE_FRICTION;
                    }

                    // increment ball x velocity a bit
                    self.ball.vel[0] += BALL_SPEED_INCREMENT *
                        self.ball.vel[0].signum();

                    Pong::correct_collision(&mut self.ball, paddle, normal);
                }

                None => {}
            }
        }

        if self.ball.pos[0] > SIZE[0] as f64 { self.score(Player::Left); }
        else if self.ball.pos[0] < 0.0 { self.score(Player::Right); }
    }

    fn correct_collision(a: &mut GameObject, b: &GameObject, normal: [f64; 2]) {
        if normal == [1.0, 0.0] {
            a.pos[0] = b.pos[0] + b.size[0] / 2.0 + a.size[0] / 2.0;
        } else if normal == [-1.0, 0.0] {
            a.pos[0] = b.pos[0] - b.size[0] / 2.0 - a.size[0] / 2.0;
        } else if normal == [0.0, 1.0] {
            a.pos[1] = b.pos[1] + b.size[1] / 2.0 + a.size[1] / 2.0;
        } else if normal == [0.0, -1.0] {
            a.pos[1] = b.pos[1] - b.size[1] / 2.0 - a.size[1] / 2.0;
        }
    }

    fn score(&mut self, player: Player) {
        match player {
            Player::Left => {
                self.server = Player::Right;
                self.p1_score += 1;
                println!("Player 1 scored! {}-{}", self.p1_score,
                    self.p2_score);
            }

            Player::Right => {
                self.server = Player::Left;
                self.p2_score += 1;
                println!("Player 2 scored! {}-{}", self.p1_score,
                    self.p2_score);
            }
        }

        self.reset();
    }
}

pub fn play() {

    let window = Window::new(OPENGL_VERSION,
        WindowSettings::new("pong", SIZE)
        .exit_on_esc(true));

    let mut pong = Pong {
        gl: GlGraphics::new(OPENGL_VERSION),
        p1: GameObject { size: PADDLE_SIZE, ..Default::default() },
        p2: GameObject { size: PADDLE_SIZE, ..Default::default() },
        ball: GameObject { size: BALL_SIZE, ..Default::default() },
        up: false,
        down: false,
        server: Player::Left,
        p1_score: 0,
        p2_score: 0,
    };

    pong.start();

    for e in window.events() {
        if let Some(r) = e.render_args() { pong.render(&r); }
        if let Some(u) = e.update_args() { pong.update(&u); }
        if let Some(Keyboard(key)) = e.press_args() { pong.key_press(key); }
        if let Some(Keyboard(key)) = e.release_args() { pong.key_release(key); }
    }
}
<|endoftext|>


<commit_before>use super::{Value, ValueRef};
use std::convert::TryInto;
use std::error::Error;
use std::fmt;

/// Enum listing possible errors from [`FromSql`] trait.
#[derive(Debug)]
#[non_exhaustive]
pub enum FromSqlError {
    /// Error when an SQLite value is requested, but the type of the result
    /// cannot be converted to the requested Rust type.
    InvalidType,

    /// Error when the i64 value returned by SQLite cannot be stored into the
    /// requested type.
    OutOfRange(i64),

    /// `feature = "i128_blob"` Error returned when reading an `i128` from a
    /// blob with a size other than 16. Only available when the `i128_blob`
    /// feature is enabled.
    #[cfg(feature = "i128_blob")]
    InvalidI128Size(usize),

    /// `feature = "uuid"` Error returned when reading a `uuid` from a blob with
    /// a size other than 16. Only available when the `uuid` feature is enabled.
    #[cfg(feature = "uuid")]
    InvalidUuidSize(usize),

    /// An error case available for implementors of the [`FromSql`] trait.
    Other(Box<dyn Error + Send + Sync + 'static>),
}

impl PartialEq for FromSqlError {
    fn eq(&self, other: &FromSqlError) -> bool {
        match (self, other) {
            (FromSqlError::InvalidType, FromSqlError::InvalidType) => true,
            (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
            #[cfg(feature = "i128_blob")]
            (FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2,
            #[cfg(feature = "uuid")]
            (FromSqlError::InvalidUuidSize(s1), FromSqlError::InvalidUuidSize(s2)) => s1 == s2,
            (..) => false,
        }
    }
}

impl fmt::Display for FromSqlError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            FromSqlError::InvalidType => write!(f, "Invalid type"),
            FromSqlError::OutOfRange(i) => write!(f, "Value {} out of range", i),
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(s) => {
                write!(f, "Cannot read 128bit value out of {} byte blob", s)
            }
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(s) => {
                write!(f, "Cannot read UUID value out of {} byte blob", s)
            }
            FromSqlError::Other(ref err) => err.fmt(f),
        }
    }
}

impl Error for FromSqlError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        if let FromSqlError::Other(ref err) = self {
            Some(&**err)
        } else {
            None
        }
    }
}

/// Result type for implementors of the [`FromSql`] trait.
pub type FromSqlResult<T> = Result<T, FromSqlError>;

/// A trait for types that can be created from a SQLite value.
///
/// Note that `FromSql` and `ToSql` are defined for most integral types, but
/// not `u64` or `usize`. This is intentional; SQLite returns integers as
/// signed 64-bit values, which cannot fully represent the range of these
/// types. Rusqlite would have to
/// decide how to handle negative values: return an error or reinterpret as a
/// very large postive numbers, neither of which
/// is guaranteed to be correct for everyone. Callers can work around this by
/// fetching values as i64 and then doing the interpretation themselves or by
/// defining a newtype and implementing `FromSql`/`ToSql` for it.
pub trait FromSql: Sized {
    /// Converts SQLite value into Rust value.
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
}

macro_rules! from_sql_integral(
    ($t:ident) => (
        impl FromSql for $t {
            #[inline]
            fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
                let i = i64::column_result(value)?;
                i.try_into().map_err(|_| FromSqlError::OutOfRange(i))
            }
        }
    )
);

from_sql_integral!(i8);
from_sql_integral!(i16);
from_sql_integral!(i32);
// from_sql_integral!(i64); // Not needed because the native type is i64.
from_sql_integral!(isize);
from_sql_integral!(u8);
from_sql_integral!(u16);
from_sql_integral!(u32);
from_sql_integral!(u64);
from_sql_integral!(usize);

impl FromSql for i64 {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_i64()
    }
}

impl FromSql for f32 {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Integer(i) => Ok(i as f32),
            ValueRef::Real(f) => Ok(f as f32),
            _ => Err(FromSqlError::InvalidType),
        }
    }
}

impl FromSql for f64 {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Integer(i) => Ok(i as f64),
            ValueRef::Real(f) => Ok(f),
            _ => Err(FromSqlError::InvalidType),
        }
    }
}

impl FromSql for bool {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        i64::column_result(value).map(|i| !matches!(i, 0))
    }
}

impl FromSql for String {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(ToString::to_string)
    }
}

impl FromSql for Box<str> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for std::rc::Rc<str> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for std::sync::Arc<str> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for Vec<u8> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_blob().map(|b| b.to_vec())
    }
}

#[cfg(feature = "i128_blob")]
impl FromSql for i128 {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        use byteorder::{BigEndian, ByteOrder};

        value.as_blob().and_then(|bytes| {
            if bytes.len() == 16 {
                Ok(BigEndian::read_i128(bytes) ^ (1i128 << 127))
            } else {
                Err(FromSqlError::InvalidI128Size(bytes.len()))
            }
        })
    }
}

#[cfg(feature = "uuid")]
impl FromSql for uuid::Uuid {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value
            .as_blob()
            .and_then(|bytes| {
                uuid::Builder::from_slice(bytes)
                    .map_err(|_| FromSqlError::InvalidUuidSize(bytes.len()))
            })
            .map(|mut builder| builder.build())
    }
}

impl<T: FromSql> FromSql for Option<T> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Null => Ok(None),
            _ => FromSql::column_result(value).map(Some),
        }
    }
}

impl FromSql for Value {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        Ok(value.into())
    }
}

#[cfg(test)]
mod test {
    use super::FromSql;
    use crate::{Connection, Error, Result};

    #[test]
    fn test_integral_ranges() -> Result<()> {
        let db = Connection::open_in_memory()?;

        fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
        where
            T: Into<i64> + FromSql + ::std::fmt::Debug,
        {
            for n in out_of_range {
                let err = db
                    .query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
                    .unwrap_err();
                match err {
                    Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
                    _ => panic!("unexpected error: {}", err),
                }
            }
            for n in in_range {
                assert_eq!(
                    *n,
                    db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
                        .unwrap()
                        .into()
                );
            }
        }

        check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]);
        check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]);
        check_ranges::<i32>(
            &db,
            &[-2_147_483_649, 2_147_483_648],
            &[-2_147_483_648, -1, 0, 1, 2_147_483_647],
        );
        check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
        check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
        check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
        Ok(())
    }
}
<commit_msg>Remove obsolete doc section<commit_after>use super::{Value, ValueRef};
use std::convert::TryInto;
use std::error::Error;
use std::fmt;

/// Enum listing possible errors from [`FromSql`] trait.
#[derive(Debug)]
#[non_exhaustive]
pub enum FromSqlError {
    /// Error when an SQLite value is requested, but the type of the result
    /// cannot be converted to the requested Rust type.
    InvalidType,

    /// Error when the i64 value returned by SQLite cannot be stored into the
    /// requested type.
    OutOfRange(i64),

    /// `feature = "i128_blob"` Error returned when reading an `i128` from a
    /// blob with a size other than 16. Only available when the `i128_blob`
    /// feature is enabled.
    #[cfg(feature = "i128_blob")]
    InvalidI128Size(usize),

    /// `feature = "uuid"` Error returned when reading a `uuid` from a blob with
    /// a size other than 16. Only available when the `uuid` feature is enabled.
    #[cfg(feature = "uuid")]
    InvalidUuidSize(usize),

    /// An error case available for implementors of the [`FromSql`] trait.
    Other(Box<dyn Error + Send + Sync + 'static>),
}

impl PartialEq for FromSqlError {
    fn eq(&self, other: &FromSqlError) -> bool {
        match (self, other) {
            (FromSqlError::InvalidType, FromSqlError::InvalidType) => true,
            (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
            #[cfg(feature = "i128_blob")]
            (FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2,
            #[cfg(feature = "uuid")]
            (FromSqlError::InvalidUuidSize(s1), FromSqlError::InvalidUuidSize(s2)) => s1 == s2,
            (..) => false,
        }
    }
}

impl fmt::Display for FromSqlError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            FromSqlError::InvalidType => write!(f, "Invalid type"),
            FromSqlError::OutOfRange(i) => write!(f, "Value {} out of range", i),
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(s) => {
                write!(f, "Cannot read 128bit value out of {} byte blob", s)
            }
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(s) => {
                write!(f, "Cannot read UUID value out of {} byte blob", s)
            }
            FromSqlError::Other(ref err) => err.fmt(f),
        }
    }
}

impl Error for FromSqlError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        if let FromSqlError::Other(ref err) = self {
            Some(&**err)
        } else {
            None
        }
    }
}

/// Result type for implementors of the [`FromSql`] trait.
pub type FromSqlResult<T> = Result<T, FromSqlError>;

/// A trait for types that can be created from a SQLite value.
pub trait FromSql: Sized {
    /// Converts SQLite value into Rust value.
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
}

macro_rules! from_sql_integral(
    ($t:ident) => (
        impl FromSql for $t {
            #[inline]
            fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
                let i = i64::column_result(value)?;
                i.try_into().map_err(|_| FromSqlError::OutOfRange(i))
            }
        }
    )
);

from_sql_integral!(i8);
from_sql_integral!(i16);
from_sql_integral!(i32);
// from_sql_integral!(i64); // Not needed because the native type is i64.
from_sql_integral!(isize);
from_sql_integral!(u8);
from_sql_integral!(u16);
from_sql_integral!(u32);
from_sql_integral!(u64);
from_sql_integral!(usize);

impl FromSql for i64 {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_i64()
    }
}

impl FromSql for f32 {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Integer(i) => Ok(i as f32),
            ValueRef::Real(f) => Ok(f as f32),
            _ => Err(FromSqlError::InvalidType),
        }
    }
}

impl FromSql for f64 {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Integer(i) => Ok(i as f64),
            ValueRef::Real(f) => Ok(f),
            _ => Err(FromSqlError::InvalidType),
        }
    }
}

impl FromSql for bool {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        i64::column_result(value).map(|i| !matches!(i, 0))
    }
}

impl FromSql for String {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(ToString::to_string)
    }
}

impl FromSql for Box<str> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for std::rc::Rc<str> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for std::sync::Arc<str> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for Vec<u8> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_blob().map(|b| b.to_vec())
    }
}

#[cfg(feature = "i128_blob")]
impl FromSql for i128 {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        use byteorder::{BigEndian, ByteOrder};

        value.as_blob().and_then(|bytes| {
            if bytes.len() == 16 {
                Ok(BigEndian::read_i128(bytes) ^ (1i128 << 127))
            } else {
                Err(FromSqlError::InvalidI128Size(bytes.len()))
            }
        })
    }
}

#[cfg(feature = "uuid")]
impl FromSql for uuid::Uuid {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value
            .as_blob()
            .and_then(|bytes| {
                uuid::Builder::from_slice(bytes)
                    .map_err(|_| FromSqlError::InvalidUuidSize(bytes.len()))
            })
            .map(|mut builder| builder.build())
    }
}

impl<T: FromSql> FromSql for Option<T> {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Null => Ok(None),
            _ => FromSql::column_result(value).map(Some),
        }
    }
}

impl FromSql for Value {
    #[inline]
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        Ok(value.into())
    }
}

#[cfg(test)]
mod test {
    use super::FromSql;
    use crate::{Connection, Error, Result};

    #[test]
    fn test_integral_ranges() -> Result<()> {
        let db = Connection::open_in_memory()?;

        fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
        where
            T: Into<i64> + FromSql + ::std::fmt::Debug,
        {
            for n in out_of_range {
                let err = db
                    .query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
                    .unwrap_err();
                match err {
                    Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
                    _ => panic!("unexpected error: {}", err),
                }
            }
            for n in in_range {
                assert_eq!(
                    *n,
                    db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
                        .unwrap()
                        .into()
                );
            }
        }

        check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]);
        check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]);
        check_ranges::<i32>(
            &db,
            &[-2_147_483_649, 2_147_483_648],
            &[-2_147_483_648, -1, 0, 1, 2_147_483_647],
        );
        check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
        check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
        check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for reading & extracting data from Multiboot 2 boot information.
//!
//! Consult the [Multiboot Specification](http://nongnu.askapache.com/grub/phcoder/multiboot.pdf)
//! for more information.
use memory::{PAddr, PhysicalPage, FrameRange};
use elf::section::{Sections, HeaderRepr as SectionHeader};

use core::iter::IntoIterator;
use core::fmt;

const END_TAG_LEN: u32 = 8;

const HEADER_LEN: u32 = 24;

pub const MAGIC: u32 = 0xe85250d6;

#[repr(u32)]
pub enum HeaderArch {
      I386 = 0
    , Mips = 4
}

#[repr(C)]
pub struct Header {
      pub magic: u32
    , pub arch: HeaderArch
    , pub header_length: u32
    , pub checksum: u32
    , pub end_tag: Tag
}

#[linkage = "external"]
#[link_section = ".multiboot_header"]
pub static HEADER: Header = Header {
    magic: MAGIC
  , arch: HeaderArch::I386
  , header_length: HEADER_LEN
  , checksum: -((MAGIC + 0 + HEADER_LEN) as i32) as u32
  , end_tag: Tag { ty: TagType::End
                 , length: END_TAG_LEN
                 }
};

#[repr(C)]
pub struct Info { pub length: u32
                , _pad: u32
                , tag_start: Tag
                }

impl Info {

    #[inline]
    pub fn start_addr(&self) -> PAddr {
        PAddr::from(self as *const _ as u64)
    }

    pub fn end_addr(&self) -> PAddr {
        PAddr::from(self.start_addr() + self.length as u64)
    }

    /// TODO: rewrite this as a `TryFrom` implementation (see issue #85)
    //          - eliza, 03/09/2017
    pub unsafe fn from(addr: PAddr) -> Result<&'static Self, &'static str> {
        let info: &Info = &*(addr.into(): u64 as *const Info);
        // TODO: check if the multiboot tag *exists* at this location as well?
        //       since if we pass in the wrong address, we'll still make the
        //       "no end tag" error.
        //
        //       which, i suppose is *technically* correct, but not very
        //       helpful...
        //          - eliza, 03/04/2017
        if info.has_end() {
            Ok(info)
        } else {
            Err( "Multiboot info structure at {:?} had no end tag!")
        }
    }

    /// Finds the tag with the given tag type.
    ///
    /// This is actually safe since the tag types are constrained by The
    /// `TagType` enum
    ///
    /// # Returns
    ///  - `Some(tag)` if a tag of the given type could be found.
    ///  - `None` if no tag of the given type could be found.
    pub fn get_tag(&'static self, tag_type: TagType) -> Option<&'static Tag> {
        self.tags()
            .find(|t| t.ty == tag_type)
    }

    /// Finds the memory map tag.
    ///
    ///  # Returns
    ///  - `Some(MemMapTag)` if a memory map tag could be found
    ///  - `None` if no tag of the given type could be found.
    #[inline]
    pub fn mem_map(&'static self) -> Option<&'static MemMapTag> {
        self.get_tag(TagType::MemoryMap)
            .map(|tag| unsafe { &*((tag as *const Tag) as *const MemMapTag) })
    }

    /// Finds the ELF sections tag.
    ///
    ///  # Returns
    ///  - `Some(ElfSectionsTag)` if a memory map tag could be found
    ///  - `None` if no tag of the given type could be found.
    #[inline]
    pub fn elf_sections(&'static self) -> Option<&'static ElfSectionsTag> {
        self.get_tag(TagType::ELFSections)
            .map(|tag| unsafe {
                &*((tag as *const Tag) as *const ElfSectionsTag)
            })
    }

    /// Returns an iterator over all Multiboot tags.
    #[inline]
    fn tags(&'static self) -> Tags { Tags(&self.tag_start as *const Tag) }

    /// Returns true if the multiboot structure has a valid end tag.
    fn has_end(&self) -> bool {
        // TODO: we should be able to use ptr::offset() here?
        //          - eliza, 03/05/2017
        let end_tag_addr
            = self as *const _ as usize +
              (self.length as usize - END_TAG_LEN as usize);
        let end_tag = unsafe {&*(end_tag_addr as *const Tag)};
        end_tag.ty == TagType::End && end_tag.length == 8
    }

    /// Returns the kernel frame range from the Multiboot 2 ELF Sections
    pub fn kernel_frames(&self) -> Result<FrameRange, &'static str> {
        let sections_tag = self.elf_sections()
                               .ok_or("ELF sections tag required!")?;

        let kernel_start = sections_tag.sections()
                              .map(|s| s.addr())
                              .min()
                              .ok_or("Couldn't find kernel start section!")?;
        let kernel_end = sections_tag.sections()
                              .map(|s| s.addr())
                              .max()
                              .ok_or("Couldn't find kernel end section!")?;

        Ok(PhysicalPage::from(kernel_start) .. PhysicalPage::from(kernel_end))
    }
}

impl IntoIterator for &'static Info {
    type IntoIter = Tags;
    type Item = &'static Tag;
    #[inline]  fn into_iter(self) -> Self::IntoIter { self.tags() }

}

/// A Multiboot tag.
///
/// From the specification:
///
/// Boot information consists of a fixed part and a series of tags.
/// Its start is 8-bytes aligned. Fixed part is as following:
///
///<rawtext>
///
///             +-------------------+
///     u32     | total_size        |
///     u32     | reserved          |
///             +-------------------+
///</rawtext>
///
/// `total_size` contains the total size of boot information including this
/// field and terminating tag in bytes.
/// `reserved` is always set to zero and must be ignored by OS image.
///
///  Every tag begins with following fields:
///<rawtext>
///
///             +-------------------+
///     u32     | type              |
///     u32     | size              |
///             +-------------------+
///</rawtext>
/// `type` contains an identifier of contents of the rest of the tag. `size`
/// contains the size of tag including header fields but not including padding.
/// Tags follow one another padded when necessary in order for each tag to
/// start at 8-bytes aligned address. Tags are terminated by a tag of type `0`
/// and size `8`.
#[repr(C)]
#[derive(Debug)]
pub struct Tag { /// the type of this tag.
                 pub ty: TagType
               , length: u32
               }

/// Types of Multiboot tags
///
/// Refer to Chapter 3 of the Multiboot 2 spec
#[repr(u32)]
#[derive(Debug, Eq, PartialEq)]
pub enum TagType { /// Tag that indicates the end of multiboot tags
                   End              = 0
                 , /// Command line passed to the bootloader
                   CommandLine      = 1
                 , BootloaderName   = 2
                 , Modules          = 3
                 , BasicMemInfo     = 4
                 , BIOSBootDev      = 5
                 , MemoryMap        = 6
                 , VBEInfo          = 7
                 , FramebufferInfo  = 8
                 , ELFSections      = 9
                 , APMTable         = 10
                 }

/// An iterator over Multiboot 2 tags.
pub struct Tags(*const Tag);

impl Tags {
    #[inline] fn advance(&mut self, size: u32) {
        let next_addr = self.0 as usize + size as usize;
        self.0 = (((next_addr-1) & !0x7) + 0x8) as *const _;
    }
}

impl Iterator for Tags {
    type Item = &'static Tag;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        match unsafe { &*self.0 } {
            &Tag { ty: TagType::End, length: END_TAG_LEN } => None
          , tag => {
              self.advance(tag.length);
              Some(tag)
            }
        }
    }
}

/// A Memory Map tag
#[repr(C)]
pub struct MemMapTag { tag: Tag
                     , pub entry_size: u32
                     , pub entry_version: u32
                     , first_entry: MemArea
                     }

impl MemMapTag {

    /// Returns an iterator over all the memory areas in this tag.
    #[inline] pub fn areas(&'static self) -> MemAreas {
        MemAreas { curr: (&self.first_entry) as *const MemArea
                    // TODO: we should be able to use ptr::offset() here?
                    //          - eliza, 03/05/2017
                 , last: ((self as *const MemMapTag as u32) +
                         self.tag.length - self.entry_size)
                         as *const MemArea
                 , size: self.entry_size
                 }
    }
}

impl IntoIterator for &'static MemMapTag {
    type Item = &'static MemArea;
    type IntoIter = MemAreas;

    #[inline] fn into_iter(self) -> Self::IntoIter { self.areas() }

}

/// A tag that stores the boot command line.
#[repr(C)]
pub struct CommandLineTag { tag: Tag
                          , /// The boot command line.
                            ///
                            /// The command line is a normal C-style zero-
                            /// terminated UTF-8 string.
                            pub command_line: [u8]
                          }

#[repr(C)]
pub struct ModulesTag { tag: Tag
                      , /// The address at which the module begins.
                        pub mod_begin: PAddr
                      , /// The address at which the module ends.
                        pub mod_end: PAddr
                      , /// A string (typically a command line)
                        pub string: [u8]
                      }

#[repr(u32)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum MemAreaType { Available = 1
                     , Acpi      = 3
                     , Preserve  = 4
                     }

/// A multiboot 2 memory area
#[repr(C)]
#[derive(Debug)]
pub struct MemArea { /// the starting address of the memory area
                     pub base: PAddr
                   , /// the length of the memory area
                     pub length: PAddr
                   , /// the type of the memory area
                     pub ty: MemAreaType
                   , _pad: u32
                   }

impl MemArea {
    #[inline] pub fn address(&self) -> PAddr {
        self.base + self.length - 1
    }
}

impl fmt::Display for MemArea {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!( f, "{:?} from {:#08x} to {:#08x}"
              , self.ty, self.base, self.address())
    }
}

/// An iterator over memory areas
#[derive(Clone)]
pub struct MemAreas { curr: *const MemArea
                    , last: *const MemArea
                    , size: u32
                    }

impl Iterator for MemAreas {
    type Item = &'static MemArea;

    fn next(&mut self) -> Option<&'static MemArea> {
        if self.curr > self.last {
            None
        } else {
            let current = unsafe { &*self.curr };
            // TODO: we should be able to use ptr::offset() here.
            //          - eliza, 03/05/2017
            self.curr = (self.curr as u32 + self.size) as *const MemArea;
            // if current.ty == MemAreaType::Available {
            // NOTE: this used to skip over unavailable or ACPI memory areas,
            //       but i've disabled that as we may want to iterate over thsoe
            //       memory areas. we can use `filter` on this iterator to get
            //       only available memory areas.
            //          - eliza, 03/05/2017
            Some(current)
            // } else {
            //      self.next()
            // }
        }
    }
}

#[cfg(target_pointer_width = "32")]
pub type Word = u32;
#[cfg(target_pointer_width = "64")]
pub type Word = u64;

/// A Multiboot 2 ELF sections tag
#[derive(Debug)]
#[repr(packed)]
pub struct ElfSectionsTag { tag: Tag
                          , /// the number of sections pointed to by this tag
                            pub n_sections: u32
                          , /// the size of each ELF section
                            pub section_size: u32
                          , stringtable_idx: u32
                          , first_section: SectionHeader<Word>
                          }

impl ElfSectionsTag {
    /// Returns an iterator over the ELF sections pointed to by this tag.
    //  TODO: can the &'static bound be reduced to &'a? is there any reason to?
    //          - eliza, 03/04/2017
    #[inline] pub fn sections(&'static self) -> Sections<'static, Word> {
        Sections::new( &self.first_section
                     , self.n_sections - 1
                     , self.section_size
                     )
    }
}

impl IntoIterator for &'static ElfSectionsTag {
    //  TODO: can the &'static bound be reduced to &'a? is there any reason to?
    //          - eliza, 03/04/2017
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = Sections<'static, Word>;

    #[inline] fn into_iter(self) -> Self::IntoIter { self.sections() }

}
<commit_msg>fix(multiboot2): use changed ELF API from 9d2eb03cd444cfa89867b1ffe202719410590cd8<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for reading & extracting data from Multiboot 2 boot information.
//!
//! Consult the [Multiboot Specification](http://nongnu.askapache.com/grub/phcoder/multiboot.pdf)
//! for more information.
use memory::{PAddr, PhysicalPage, FrameRange};
use elf::section::{Sections, HeaderRepr as SectionHeader};

use core::iter::IntoIterator;
use core::fmt;

const END_TAG_LEN: u32 = 8;

const HEADER_LEN: u32 = 24;

pub const MAGIC: u32 = 0xe85250d6;

#[repr(u32)]
pub enum HeaderArch {
      I386 = 0
    , Mips = 4
}

#[repr(C)]
pub struct Header {
      pub magic: u32
    , pub arch: HeaderArch
    , pub header_length: u32
    , pub checksum: u32
    , pub end_tag: Tag
}

#[linkage = "external"]
#[link_section = ".multiboot_header"]
pub static HEADER: Header = Header {
    magic: MAGIC
  , arch: HeaderArch::I386
  , header_length: HEADER_LEN
  , checksum: -((MAGIC + 0 + HEADER_LEN) as i32) as u32
  , end_tag: Tag { ty: TagType::End
                 , length: END_TAG_LEN
                 }
};

#[repr(C)]
pub struct Info { pub length: u32
                , _pad: u32
                , tag_start: Tag
                }

impl Info {

    #[inline]
    pub fn start_addr(&self) -> PAddr {
        PAddr::from(self as *const _ as u64)
    }

    pub fn end_addr(&self) -> PAddr {
        PAddr::from(self.start_addr() + self.length as u64)
    }

    /// TODO: rewrite this as a `TryFrom` implementation (see issue #85)
    //          - eliza, 03/09/2017
    pub unsafe fn from(addr: PAddr) -> Result<&'static Self, &'static str> {
        let info: &Info = &*(addr.into(): u64 as *const Info);
        // TODO: check if the multiboot tag *exists* at this location as well?
        //       since if we pass in the wrong address, we'll still make the
        //       "no end tag" error.
        //
        //       which, i suppose is *technically* correct, but not very
        //       helpful...
        //          - eliza, 03/04/2017
        if info.has_end() {
            Ok(info)
        } else {
            Err( "Multiboot info structure at {:?} had no end tag!")
        }
    }

    /// Finds the tag with the given tag type.
    ///
    /// This is actually safe since the tag types are constrained by The
    /// `TagType` enum
    ///
    /// # Returns
    ///  - `Some(tag)` if a tag of the given type could be found.
    ///  - `None` if no tag of the given type could be found.
    pub fn get_tag(&'static self, tag_type: TagType) -> Option<&'static Tag> {
        self.tags()
            .find(|t| t.ty == tag_type)
    }

    /// Finds the memory map tag.
    ///
    ///  # Returns
    ///  - `Some(MemMapTag)` if a memory map tag could be found
    ///  - `None` if no tag of the given type could be found.
    #[inline]
    pub fn mem_map(&'static self) -> Option<&'static MemMapTag> {
        self.get_tag(TagType::MemoryMap)
            .map(|tag| unsafe { &*((tag as *const Tag) as *const MemMapTag) })
    }

    /// Finds the ELF sections tag.
    ///
    ///  # Returns
    ///  - `Some(ElfSectionsTag)` if a memory map tag could be found
    ///  - `None` if no tag of the given type could be found.
    #[inline]
    pub fn elf_sections(&'static self) -> Option<&'static ElfSectionsTag> {
        self.get_tag(TagType::ELFSections)
            .map(|tag| unsafe {
                &*((tag as *const Tag) as *const ElfSectionsTag)
            })
    }

    /// Returns an iterator over all Multiboot tags.
    #[inline]
    fn tags(&'static self) -> Tags { Tags(&self.tag_start as *const Tag) }

    /// Returns true if the multiboot structure has a valid end tag.
    fn has_end(&self) -> bool {
        // TODO: we should be able to use ptr::offset() here?
        //          - eliza, 03/05/2017
        let end_tag_addr
            = self as *const _ as usize +
              (self.length as usize - END_TAG_LEN as usize);
        let end_tag = unsafe {&*(end_tag_addr as *const Tag)};
        end_tag.ty == TagType::End && end_tag.length == 8
    }

    /// Returns the kernel frame range from the Multiboot 2 ELF Sections
    pub fn kernel_frames(&self) -> Result<FrameRange, &'static str> {
        let sections_tag = self.elf_sections()
                               .ok_or("ELF sections tag required!")?;

        let kernel_start = sections_tag.sections()
                              .map(|s| s.address())
                              .min()
                              .ok_or("Couldn't find kernel start section!")?;
        let kernel_end = sections_tag.sections()
                              .map(|s| s.address())
                              .max()
                              .ok_or("Couldn't find kernel end section!")?;

        Ok(PhysicalPage::from(kernel_start) .. PhysicalPage::from(kernel_end))
    }
}

impl IntoIterator for &'static Info {
    type IntoIter = Tags;
    type Item = &'static Tag;
    #[inline]  fn into_iter(self) -> Self::IntoIter { self.tags() }

}

/// A Multiboot tag.
///
/// From the specification:
///
/// Boot information consists of a fixed part and a series of tags.
/// Its start is 8-bytes aligned. Fixed part is as following:
///
///<rawtext>
///
///             +-------------------+
///     u32     | total_size        |
///     u32     | reserved          |
///             +-------------------+
///</rawtext>
///
/// `total_size` contains the total size of boot information including this
/// field and terminating tag in bytes.
/// `reserved` is always set to zero and must be ignored by OS image.
///
///  Every tag begins with following fields:
///<rawtext>
///
///             +-------------------+
///     u32     | type              |
///     u32     | size              |
///             +-------------------+
///</rawtext>
/// `type` contains an identifier of contents of the rest of the tag. `size`
/// contains the size of tag including header fields but not including padding.
/// Tags follow one another padded when necessary in order for each tag to
/// start at 8-bytes aligned address. Tags are terminated by a tag of type `0`
/// and size `8`.
#[repr(C)]
#[derive(Debug)]
pub struct Tag { /// the type of this tag.
                 pub ty: TagType
               , length: u32
               }

/// Types of Multiboot tags
///
/// Refer to Chapter 3 of the Multiboot 2 spec
#[repr(u32)]
#[derive(Debug, Eq, PartialEq)]
pub enum TagType { /// Tag that indicates the end of multiboot tags
                   End              = 0
                 , /// Command line passed to the bootloader
                   CommandLine      = 1
                 , BootloaderName   = 2
                 , Modules          = 3
                 , BasicMemInfo     = 4
                 , BIOSBootDev      = 5
                 , MemoryMap        = 6
                 , VBEInfo          = 7
                 , FramebufferInfo  = 8
                 , ELFSections      = 9
                 , APMTable         = 10
                 }

/// An iterator over Multiboot 2 tags.
pub struct Tags(*const Tag);

impl Tags {
    #[inline] fn advance(&mut self, size: u32) {
        let next_addr = self.0 as usize + size as usize;
        self.0 = (((next_addr-1) & !0x7) + 0x8) as *const _;
    }
}

impl Iterator for Tags {
    type Item = &'static Tag;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        match unsafe { &*self.0 } {
            &Tag { ty: TagType::End, length: END_TAG_LEN } => None
          , tag => {
              self.advance(tag.length);
              Some(tag)
            }
        }
    }
}

/// A Memory Map tag
#[repr(C)]
pub struct MemMapTag { tag: Tag
                     , pub entry_size: u32
                     , pub entry_version: u32
                     , first_entry: MemArea
                     }

impl MemMapTag {

    /// Returns an iterator over all the memory areas in this tag.
    #[inline] pub fn areas(&'static self) -> MemAreas {
        MemAreas { curr: (&self.first_entry) as *const MemArea
                    // TODO: we should be able to use ptr::offset() here?
                    //          - eliza, 03/05/2017
                 , last: ((self as *const MemMapTag as u32) +
                         self.tag.length - self.entry_size)
                         as *const MemArea
                 , size: self.entry_size
                 }
    }
}

impl IntoIterator for &'static MemMapTag {
    type Item = &'static MemArea;
    type IntoIter = MemAreas;

    #[inline] fn into_iter(self) -> Self::IntoIter { self.areas() }

}

/// A tag that stores the boot command line.
#[repr(C)]
pub struct CommandLineTag { tag: Tag
                          , /// The boot command line.
                            ///
                            /// The command line is a normal C-style zero-
                            /// terminated UTF-8 string.
                            pub command_line: [u8]
                          }

#[repr(C)]
pub struct ModulesTag { tag: Tag
                      , /// The address at which the module begins.
                        pub mod_begin: PAddr
                      , /// The address at which the module ends.
                        pub mod_end: PAddr
                      , /// A string (typically a command line)
                        pub string: [u8]
                      }

#[repr(u32)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum MemAreaType { Available = 1
                     , Acpi      = 3
                     , Preserve  = 4
                     }

/// A multiboot 2 memory area
#[repr(C)]
#[derive(Debug)]
pub struct MemArea { /// the starting address of the memory area
                     pub base: PAddr
                   , /// the length of the memory area
                     pub length: PAddr
                   , /// the type of the memory area
                     pub ty: MemAreaType
                   , _pad: u32
                   }

impl MemArea {
    #[inline] pub fn address(&self) -> PAddr {
        self.base + self.length - 1
    }
}

impl fmt::Display for MemArea {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!( f, "{:?} from {:#08x} to {:#08x}"
              , self.ty, self.base, self.address())
    }
}

/// An iterator over memory areas
#[derive(Clone)]
pub struct MemAreas { curr: *const MemArea
                    , last: *const MemArea
                    , size: u32
                    }

impl Iterator for MemAreas {
    type Item = &'static MemArea;

    fn next(&mut self) -> Option<&'static MemArea> {
        if self.curr > self.last {
            None
        } else {
            let current = unsafe { &*self.curr };
            // TODO: we should be able to use ptr::offset() here.
            //          - eliza, 03/05/2017
            self.curr = (self.curr as u32 + self.size) as *const MemArea;
            // if current.ty == MemAreaType::Available {
            // NOTE: this used to skip over unavailable or ACPI memory areas,
            //       but i've disabled that as we may want to iterate over thsoe
            //       memory areas. we can use `filter` on this iterator to get
            //       only available memory areas.
            //          - eliza, 03/05/2017
            Some(current)
            // } else {
            //      self.next()
            // }
        }
    }
}

#[cfg(target_pointer_width = "32")]
pub type Word = u32;
#[cfg(target_pointer_width = "64")]
pub type Word = u64;

/// A Multiboot 2 ELF sections tag
#[derive(Debug)]
#[repr(packed)]
pub struct ElfSectionsTag { tag: Tag
                          , /// the number of sections pointed to by this tag
                            pub n_sections: u32
                          , /// the size of each ELF section
                            pub section_size: u32
                          , stringtable_idx: u32
                          , first_section: SectionHeader<Word>
                          }

impl ElfSectionsTag {
    /// Returns an iterator over the ELF sections pointed to by this tag.
    //  TODO: can the &'static bound be reduced to &'a? is there any reason to?
    //          - eliza, 03/04/2017
    #[inline] pub fn sections(&'static self) -> Sections<'static, Word> {
        Sections::new( &self.first_section
                     , self.n_sections - 1
                     , self.section_size
                     )
    }
}

impl IntoIterator for &'static ElfSectionsTag {
    //  TODO: can the &'static bound be reduced to &'a? is there any reason to?
    //          - eliza, 03/04/2017
    type Item = <Self::IntoIter as Iterator>::Item;
    type IntoIter = Sections<'static, Word>;

    #[inline] fn into_iter(self) -> Self::IntoIter { self.sections() }

}
<|endoftext|>


<commit_before>use crate::command_prelude::*;
use cargo::ops::tree;
use std::str::FromStr;

pub fn cli() -> App {
    subcommand("tree")
        .about("Display a tree visualization of a dependency graph")
        .arg(opt("quiet", "Suppress status messages").short("q"))
        .arg_manifest_path()
        .arg_package_spec_no_all(
            "Package to be used as the root of the tree",
            "Display the tree for all packages in the workspace",
            "Exclude specific workspace members",
        )
        .arg(Arg::with_name("all").long("all").short("a").hidden(true))
        .arg_features()
        .arg_target_triple(
            "Filter dependencies matching the given target-triple (default host platform)",
        )
        .arg(opt("no-dev-dependencies", "Skip dev dependencies"))
        .arg(opt("invert", "Invert the tree direction").short("i"))
        .arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
        .arg(
            Arg::with_name("prefix-depth")
                .long("prefix-depth")
                .hidden(true),
        )
        .arg(
            opt(
                "prefix",
                "Change the prefix (indentation) of how each entry is displayed",
            )
            .value_name("PREFIX")
            .possible_values(&["depth", "indent", "none"])
            .default_value("indent"),
        )
        .arg(opt(
            "no-dedupe",
            "Do not de-duplicate (repeats all shared dependencies)",
        ))
        .arg(
            opt(
                "duplicates",
                "Show only dependencies which come in multiple versions (implies -i)",
            )
            .short("d")
            .alias("duplicate"),
        )
        .arg(
            opt("charset", "Character set to use in output: utf8, ascii")
                .value_name("CHARSET")
                .possible_values(&["utf8", "ascii"])
                .default_value("utf8"),
        )
        .arg(
            opt("format", "Format string used for printing dependencies")
                .value_name("FORMAT")
                .short("f")
                .default_value("{p}"),
        )
        .arg(opt("graph-features", "Include features in the tree"))
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    if args.is_present("no-indent") {
        return Err(
            anyhow::format_err!("the --no-indent flag has been changed to --prefix=none").into(),
        );
    }
    if args.is_present("prefix-depth") {
        return Err(anyhow::format_err!(
            "the --prefix-depth flag has been changed to --prefix=depth"
        )
        .into());
    }
    if args.is_present("all") {
        return Err(anyhow::format_err!(
            "The `cargo tree` --all flag has been changed to --no-dedupe.\n\
            If you are looking to display all workspace members, use the --workspace flag."
        )
        .into());
    }
    let ws = args.workspace(config)?;
    let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let prefix = tree::Prefix::from_str(args.value_of("prefix").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let target = tree::Target::from_cli(args.value_of("target"));
    let opts = tree::TreeOptions {
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        packages: args.packages_from_flags()?,
        target,
        no_dev_dependencies: args.is_present("no-dev-dependencies"),
        invert: args.is_present("invert"),
        prefix,
        no_dedupe: args.is_present("no-dedupe"),
        duplicates: args.is_present("duplicates"),
        charset,
        format: args.value_of("format").unwrap().to_string(),
        graph_features: args.is_present("graph-features"),
    };

    tree::build_and_print(&ws, &opts)?;
    Ok(())
}
<commit_msg>Add hint about removal of --all-targets<commit_after>use crate::command_prelude::*;
use cargo::ops::tree;
use std::str::FromStr;

pub fn cli() -> App {
    subcommand("tree")
        .about("Display a tree visualization of a dependency graph")
        .arg(opt("quiet", "Suppress status messages").short("q"))
        .arg_manifest_path()
        .arg_package_spec_no_all(
            "Package to be used as the root of the tree",
            "Display the tree for all packages in the workspace",
            "Exclude specific workspace members",
        )
        .arg(Arg::with_name("all").long("all").short("a").hidden(true))
        .arg(
            Arg::with_name("all-targets")
                .long("all-targets")
                .hidden(true),
        )
        .arg_features()
        .arg_target_triple(
            "Filter dependencies matching the given target-triple (default host platform)",
        )
        .arg(opt("no-dev-dependencies", "Skip dev dependencies"))
        .arg(opt("invert", "Invert the tree direction").short("i"))
        .arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
        .arg(
            Arg::with_name("prefix-depth")
                .long("prefix-depth")
                .hidden(true),
        )
        .arg(
            opt(
                "prefix",
                "Change the prefix (indentation) of how each entry is displayed",
            )
            .value_name("PREFIX")
            .possible_values(&["depth", "indent", "none"])
            .default_value("indent"),
        )
        .arg(opt(
            "no-dedupe",
            "Do not de-duplicate (repeats all shared dependencies)",
        ))
        .arg(
            opt(
                "duplicates",
                "Show only dependencies which come in multiple versions (implies -i)",
            )
            .short("d")
            .alias("duplicate"),
        )
        .arg(
            opt("charset", "Character set to use in output: utf8, ascii")
                .value_name("CHARSET")
                .possible_values(&["utf8", "ascii"])
                .default_value("utf8"),
        )
        .arg(
            opt("format", "Format string used for printing dependencies")
                .value_name("FORMAT")
                .short("f")
                .default_value("{p}"),
        )
        .arg(opt("graph-features", "Include features in the tree"))
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    if args.is_present("no-indent") {
        return Err(
            anyhow::format_err!("the --no-indent flag has been changed to --prefix=none").into(),
        );
    }
    if args.is_present("prefix-depth") {
        return Err(anyhow::format_err!(
            "the --prefix-depth flag has been changed to --prefix=depth"
        )
        .into());
    }
    if args.is_present("all") {
        return Err(anyhow::format_err!(
            "The `cargo tree` --all flag has been changed to --no-dedupe.\n\
            If you are looking to display all workspace members, use the --workspace flag."
        )
        .into());
    }
    if args.is_present("all-targets") {
        return Err(
            anyhow::format_err!("the --all-targets flag has been changed to --target=all").into(),
        );
    }
    let ws = args.workspace(config)?;
    let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let prefix = tree::Prefix::from_str(args.value_of("prefix").unwrap())
        .map_err(|e| anyhow::anyhow!("{}", e))?;
    let target = tree::Target::from_cli(args.value_of("target"));
    let opts = tree::TreeOptions {
        features: values(args, "features"),
        all_features: args.is_present("all-features"),
        no_default_features: args.is_present("no-default-features"),
        packages: args.packages_from_flags()?,
        target,
        no_dev_dependencies: args.is_present("no-dev-dependencies"),
        invert: args.is_present("invert"),
        prefix,
        no_dedupe: args.is_present("no-dedupe"),
        duplicates: args.is_present("duplicates"),
        charset,
        format: args.value_of("format").unwrap().to_string(),
        graph_features: args.is_present("graph-features"),
    };

    tree::build_and_print(&ws, &opts)?;
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Fabian Schuiki

//! Type declarations and references to them.

use std::fmt::{self, Debug, Display};

use common::name::Name;
use common::source::Span;

use ty2::{Type, AnyType, Subtype};

/// A type name.
///
/// Types can be declared by the user or be provided as a builtin. In the case
/// of a user-defined type we would like to keep track of its `Span` for good
/// error messages. Builtin types have no location we can refer to however, and
/// we must rather keep track of the name directly.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum TypeName {
	/// The name is defined through an internalized name.
	Name(Name),
	/// The name is defined through a span.
	Span(Span),
}

impl From<Name> for TypeName {
	fn from(name: Name) -> TypeName {
		TypeName::Name(name)
	}
}

impl From<Span> for TypeName {
	fn from(span: Span) -> TypeName {
		TypeName::Span(span)
	}
}

impl TypeName {
	/// Get the type name as a string.
	pub fn to_string(self) -> String {
		match self {
			TypeName::Name(name) => name.into(),
			TypeName::Span(span) => span.extract(),
		}
	}

	/// Get the type name as a `Name`.
	///
	/// Returns `None` if the type name is given through a `Span`.
	pub fn as_name(self) -> Option<Name> {
		match self {
			TypeName::Name(name) => Some(name),
			_ => None,
		}
	}

	/// Get the type name as a `Span`.
	///
	/// Returns `None` if the type name is given as a `Name`.
	pub fn as_span(self) -> Option<Span> {
		match self {
			TypeName::Span(span) => Some(span),
			_ => None,
		}
	}
}

impl Display for TypeName {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			TypeName::Name(name) => write!(f, "{}", name),
			TypeName::Span(span) => write!(f, "{}", span.extract()),
		}
	}
}

impl Debug for TypeName {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		Display::fmt(self, f)
	}
}

/// A type declaration.
///
/// A `TypeDecl` associates a name with a type. It is useful as a tracker of how
/// a type was called upon its definition, and where it was defined.
///
/// # Examples
///
/// ```
/// use moore_vhdl::ty2::{Type, TypeDecl, IntegerType, Range};
/// use moore_vhdl::common::name::get_name_table;
///
/// let ta = IntegerType::new(Range::descending(31, 0));
/// let a = TypeDecl::new(
///     get_name_table().intern("DATA", false),
///     &ta,
/// );
///
/// assert_eq!(format!("{}", a), "type DATA is 31 downto 0");
/// ```
#[derive(Clone, Copy, Debug)]
pub struct TypeDecl<'t> {
	name: TypeName,
	ty: &'t Type,
}

impl<'t> TypeDecl<'t> {
	/// Create a new type declaration from a name and a type.
	pub fn new<N: Into<TypeName>>(name: N, ty: &'t Type) -> TypeDecl<'t> {
		TypeDecl {
			name: name.into(),
			ty: ty,
		}
	}

	/// Get the name of the declared type.
	pub fn name(&self) -> TypeName {
		self.name
	}

	/// Get the declared type.
	pub fn ty(&self) -> &'t Type {
		self.ty
	}
}

impl<'t> Type for TypeDecl<'t> {
    fn is_scalar(&self) -> bool { self.ty.is_scalar() }
    fn is_discrete(&self) -> bool { self.ty.is_discrete() }
    fn is_numeric(&self) -> bool { self.ty.is_numeric() }
    fn is_composite(&self) -> bool { self.ty.is_composite() }
    fn as_any(&self) -> AnyType { self.ty.as_any() }
}

impl<'t> Display for TypeDecl<'t> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "type {} is {}", self.name, self.ty)
	}
}

/// A subtype declaration.
///
/// A `SubtypeDecl` associates a name with a subtype. It is useful as a tracker
/// of how a subtype was called upon its definition, and where it was defined.
pub struct SubtypeDecl<'t> {
	name: TypeName,
	ty: &'t Subtype, // TODO: Actually make this a subtype indication.
}
<commit_msg>vhdl: add type marks<commit_after>// Copyright (c) 2017-2018 Fabian Schuiki

//! Type declarations and references to them.

use std::fmt::{self, Debug, Display};

use common::name::Name;
use common::source::Span;

use ty2::{Type, AnyType, Subtype};

/// A type name.
///
/// Types can be declared by the user or be provided as a builtin. In the case
/// of a user-defined type we would like to keep track of its `Span` for good
/// error messages. Builtin types have no location we can refer to however, and
/// we must rather keep track of the name directly.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum TypeName {
	/// The name is defined through an internalized name.
	Name(Name),
	/// The name is defined through a span.
	Span(Span),
}

impl From<Name> for TypeName {
	fn from(name: Name) -> TypeName {
		TypeName::Name(name)
	}
}

impl From<Span> for TypeName {
	fn from(span: Span) -> TypeName {
		TypeName::Span(span)
	}
}

impl TypeName {
	/// Get the type name as a string.
	pub fn to_string(self) -> String {
		match self {
			TypeName::Name(name) => name.into(),
			TypeName::Span(span) => span.extract(),
		}
	}

	/// Get the type name as a `Name`.
	///
	/// Returns `None` if the type name is given through a `Span`.
	pub fn as_name(self) -> Option<Name> {
		match self {
			TypeName::Name(name) => Some(name),
			_ => None,
		}
	}

	/// Get the type name as a `Span`.
	///
	/// Returns `None` if the type name is given as a `Name`.
	pub fn as_span(self) -> Option<Span> {
		match self {
			TypeName::Span(span) => Some(span),
			_ => None,
		}
	}
}

impl Display for TypeName {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			TypeName::Name(name) => write!(f, "{}", name),
			TypeName::Span(span) => write!(f, "{}", span.extract()),
		}
	}
}

impl Debug for TypeName {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		Display::fmt(self, f)
	}
}

/// A type declaration.
///
/// A `TypeDecl` associates a name with a type. It is useful as a tracker of how
/// a type was called upon its definition, and where it was defined.
///
/// # Examples
///
/// ```
/// use moore_vhdl::ty2::{Type, TypeDecl, IntegerType, Range};
/// use moore_vhdl::common::name::get_name_table;
///
/// let ta = IntegerType::new(Range::descending(31, 0));
/// let a = TypeDecl::new(
///     get_name_table().intern("DATA", false),
///     &ta,
/// );
///
/// assert_eq!(format!("{}", a), "type DATA is 31 downto 0");
/// ```
#[derive(Clone, Copy, Debug)]
pub struct TypeDecl<'t> {
	name: TypeName,
	ty: &'t Type,
}

impl<'t> TypeDecl<'t> {
	/// Create a new type declaration from a name and a type.
	pub fn new<N: Into<TypeName>>(name: N, ty: &'t Type) -> TypeDecl<'t> {
		TypeDecl {
			name: name.into(),
			ty: ty,
		}
	}

	/// Get the name of the declared type.
	pub fn name(&self) -> TypeName {
		self.name
	}

	/// Get the declared type.
	pub fn ty(&self) -> &'t Type {
		self.ty
	}
}

impl<'t> Type for TypeDecl<'t> {
    fn is_scalar(&self) -> bool { self.ty.is_scalar() }
    fn is_discrete(&self) -> bool { self.ty.is_discrete() }
    fn is_numeric(&self) -> bool { self.ty.is_numeric() }
    fn is_composite(&self) -> bool { self.ty.is_composite() }
    fn as_any(&self) -> AnyType { self.ty.as_any() }
}

impl<'t> Display for TypeDecl<'t> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "type {} is {}", self.name, self.ty)
	}
}

/// A subtype declaration.
///
/// A `SubtypeDecl` associates a name with a subtype. It is useful as a tracker
/// of how a subtype was called upon its definition, and where it was defined.
#[derive(Clone, Copy, Debug)]
pub struct SubtypeDecl<'t> {
	name: TypeName,
	ty: &'t Subtype, // TODO: Actually make this a subtype indication.
}

/// A type mark.
///
/// A `TypeMark` associates a name with a type or subtype, but in a different
/// manner than `TypeDecl` and `SubtypeDecl`. It is useful as a tracker of how a
/// type was referred to in the source code. A `TypeMark` represents a way of
/// naming a type that is familiar to the user and can be presented as is in a
/// diagnostic message.
///
/// # Examples
///
/// ```
/// use moore_vhdl::ty2::{Type, TypeMark, NullType};
/// use moore_vhdl::common::name::get_name_table;
///
/// let ta = NullType;
/// let a = TypeMark::new(
///     get_name_table().intern("DATA", false),
///     &ta,
/// );
///
/// assert_eq!(format!("{}", a), "DATA");
/// ```
#[derive(Clone, Copy, Debug)]
pub struct TypeMark<'t> {
	name: TypeName,
	ty: &'t Type,
}

impl<'t> TypeMark<'t> {
	/// Create a new type mark from a name and a type.
	pub fn new<N: Into<TypeName>>(name: N, ty: &'t Type) -> TypeMark<'t> {
		TypeMark {
			name: name.into(),
			ty: ty,
		}
	}

	/// Get the name of the mark.
	pub fn name(&self) -> TypeName {
		self.name
	}

	/// Get the type of the mark.
	pub fn ty(&self) -> &'t Type {
		self.ty
	}
}

impl<'t> Type for TypeMark<'t> {
    fn is_scalar(&self) -> bool { self.ty.is_scalar() }
    fn is_discrete(&self) -> bool { self.ty.is_discrete() }
    fn is_numeric(&self) -> bool { self.ty.is_numeric() }
    fn is_composite(&self) -> bool { self.ty.is_composite() }
    fn as_any(&self) -> AnyType { self.ty.as_any() }
}

impl<'t> Display for TypeMark<'t> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.name)
	}
}
<|endoftext|>