<commit_before>extern crate time;

use std::fs::{OpenOptions};
use std::io::{BufReader, BufWriter};
use std::io::prelude::*;
use std::env;

fn show_notes() {
    let file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("NOTES.TXT")
        .unwrap();
    let mut buf_reader = BufReader::new(file);
    let mut contents = String::new();
    buf_reader.read_to_string(&mut contents).unwrap();
    println!("{}", contents);
}

fn add_to_notes(note: &str) {
    let file = OpenOptions::new()
        .append(true)
        .create(true)
        .open("NOTES.TXT")
        .unwrap();
    let mut buf_writer = BufWriter::new(file);

    let now = time::now();
    let date_and_time = now.asctime();
    writeln!(buf_writer, "{}", date_and_time).unwrap();

    writeln!(buf_writer, "\t{}", note).unwrap();
}

fn main() {
    let note = env::args().skip(1).collect::<Vec<_>>();

    if note.is_empty() {
        show_notes();
    } else {
        add_to_notes(&note.join(" "));
    }
}
<commit_msg>improve error handling, switch to chrono crate<commit_after>extern crate chrono;

use std::fs::OpenOptions;
use std::io::{self, BufReader, BufWriter};
use std::io::prelude::*;
use std::env;

const FILENAME: &str = "NOTES.TXT";

fn show_notes() -> Result<(), io::Error> {
    let file = OpenOptions::new()
        .read(true)
        .create(true) // create the file if not found
        .write(true) // necessary to create the file
        .open(FILENAME)?;
    let mut buf_reader = BufReader::new(file);
    let mut contents = String::new();
    buf_reader.read_to_string(&mut contents)?;
    println!("{}", contents);
    Ok(())
}

fn add_to_notes(note: &str) -> Result<(), io::Error> {
    let file = OpenOptions::new()
        .append(true) // disables overwriting, writes to the end of the file
        .create(true)
        .open(FILENAME)?;
    let mut buf_writer = BufWriter::new(file);

    let date_and_time = chrono::Local::now();
    writeln!(buf_writer, "{}", date_and_time)?;

    writeln!(buf_writer, "\t{}", note)
}

fn main() {
    let note = env::args().skip(1).collect::<Vec<_>>();

    if note.is_empty() {
        show_notes().expect("failed to print NOTES.TXT");
    } else {
        add_to_notes(&note.join(" ")).expect("failed to write to NOTES.TXT");
    }
}
<|endoftext|>


<commit_before>// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
//
// Example 2-5: Forces (Gravity and Fluid Resistence) with Vectors
//
// Demonstration of multiple forces acting on bodies (Mover type)
// Bodies experience gravity continuously
// Bodies experience fluid resistance when in *water*
use nannou::prelude::*;

fn main() {
    nannou::app(model).update(update).run();
}

struct Model {
    movers: Vec<Mover>,
    liquid: Liquid,
}

struct Mover {
    position: Point2,
    velocity: Vector2,
    acceleration: Vector2,
    mass: f32,
}

// Liquid type
struct Liquid {
    // Liquid is a rectangle
    rect: Rect,
    // Coefficient of drag
    c: f32,
}

impl Liquid {
    fn new(rect: Rect, c: f32) -> Self {
        let rect = rect;
        let c = c;
        Liquid { rect, c }
    }

    // Is the Mover in the liquid?
    fn contains(&self, m: &Mover) -> bool {
        self.rect.contains(m.position)
    }

    // Calculate drag force
    fn drag(&self, m: &Mover) -> Vector2 {
        // Magnitude is coefficient * speed squared
        let speed = m.velocity.magnitude();
        let drag_magnitude = self.c * speed * speed;

        // Direction is inverse of velocity
        let mut drag_force = m.velocity;
        drag_force *= -1.0;

        // Scale according to magnitude
        drag_force = drag_force.normalize();
        drag_force *= drag_magnitude;
        drag_force
    }

    fn display(&self, draw: &app::Draw) {
        draw.rect()
            .xy(self.rect.xy())
            .wh(self.rect.wh())
            .rgb(0.1, 0.1, 0.1);
    }
}

impl Mover {
    fn new(m: f32, x: f32, y: f32) -> Self {
        // Mass is tied to size
        let mass = m;
        let position = pt2(x, y);
        let velocity = vec2(0.0, 0.0);
        let acceleration = vec2(0.0, 0.0);
        Mover {
            position,
            velocity,
            acceleration,
            mass,
        }
    }

    fn new_random(rect: &Rect) -> Self {
        Mover::new(
            random_range(0.5f32, 4.0),
            random_range(rect.left(), rect.right()),
            rect.top(),
        )
    }

    // Newton's 2nd law: F = M * A
    // or A = F / M
    fn apply_force(&mut self, force: Vector2) {
        // Divide by mass
        let f = force / self.mass;
        // Accumulate all forces in acceleration
        self.acceleration += f;
    }

    fn update(&mut self) {
        // Velocity changes according to acceleration
        self.velocity += self.acceleration;
        // Position changes by velocity
        self.position += self.velocity;
        // We must clear acceleration each frame
        self.acceleration *= 0.0;
    }

    // Draw Mover
    fn display(&self, draw: &app::Draw) {
        draw.ellipse()
            .xy(self.position)
            .w_h(self.mass * 16.0, self.mass * 16.0)
            .rgba(0.0, 0.0, 0.0, 0.5);
    }

    // Bounce off bottom of window
    fn check_edges(&mut self, rect: Rect) {
        if self.position.y < rect.bottom() {
            self.velocity.y *= -0.9; // A little dampening when hitting the bottom
            self.position.y = rect.bottom();
        }
    }
}

fn model(app: &App) -> Model {
    let rect = Rect::from_w_h(640.0, 360.0);
    app.new_window()
        .with_dimensions(rect.w() as u32, rect.h() as u32)
        .mouse_pressed(mouse_pressed)
        .view(view)
        .build()
        .unwrap();

    // Nine moving bodies
    let movers = (0..9)
        .map(|_| {
            Mover::new(
                random_range(1.0f32, 4.0),
                random_range(rect.left(), rect.right()),
                rect.top(),
            )
        })
        .collect();

    // Create an instance of our Liquid type
    let rect = Rect::from_w_h(rect.w(), rect.h() * 0.5).align_bottom_of(rect);
    let liquid = Liquid::new(rect, 0.1);

    Model { movers, liquid }
}

fn mouse_pressed(app: &App, m: &mut Model, _button: MouseButton) {
    // Restart all the Mover objects randomly
    for mover in &mut m.movers {
        *mover = Mover::new_random(&app.window_rect());
    }
}

fn update(app: &App, m: &mut Model, _update: Update) {
    for i in 0..m.movers.len() {
        // Is the Mover in the liquid?
        if m.liquid.contains(&m.movers[i]) {
            let drag_force = m.liquid.drag(&m.movers[i]);
            // Apply drag force to Mover
            m.movers[i].apply_force(drag_force);
        }

        // Gravity is scaled by mass here!
        let gravity = vec2(0.0, -0.1 * m.movers[i].mass);

        // Apply gravity
        m.movers[i].apply_force(gravity);
        m.movers[i].update();
        m.movers[i].check_edges(app.window_rect());
    }
}

fn view(app: &App, m: &Model, frame: Frame) -> Frame {
    // Begin drawing
    let draw = app.draw();
    draw.background().color(WHITE);

    // Draw water
    m.liquid.display(&draw);

    // Draw movers
    for mover in &m.movers {
        mover.display(&draw);
    }

    // Write the result of our drawing to the window's OpenGL frame.
    draw.to_frame(app, &frame).unwrap();

    // Return the drawn frame.
    frame
}
<commit_msg>Refactor Nature of Code's 2_5 example<commit_after>// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com
//
// Example 2-5: Forces (Gravity and Fluid Resistence) with Vectors
//
// Demonstration of multiple forces acting on bodies (Mover type)
// Bodies experience gravity continuously
// Bodies experience fluid resistance when in *water*
use nannou::prelude::*;

fn main() {
    nannou::app(model).update(update).run();
}

struct Model {
    movers: Vec<Mover>,
    liquid: Liquid,
}

struct Mover {
    position: Point2,
    velocity: Vector2,
    acceleration: Vector2,
    mass: f32,
}

// Liquid type
struct Liquid {
    // Liquid is a rectangle
    rect: Rect,
    // Coefficient of drag
    c: f32,
}

impl Liquid {
    fn new(rect: Rect, c: f32) -> Self {
        let rect = rect;
        let c = c;
        Liquid { rect, c }
    }

    // Is the Mover in the liquid?
    fn contains(&self, m: &Mover) -> bool {
        self.rect.contains(m.position)
    }

    // Calculate drag force
    fn drag(&self, m: &Mover) -> Vector2 {
        // Magnitude is coefficient * speed squared
        let speed = m.velocity.magnitude();
        let drag_magnitude = self.c * speed * speed;

        // Direction is inverse of velocity
        let mut drag_force = m.velocity;
        drag_force *= -1.0;

        // Scale according to magnitude
        drag_force = drag_force.normalize();
        drag_force *= drag_magnitude;
        drag_force
    }

    fn display(&self, draw: &app::Draw) {
        draw.rect()
            .xy(self.rect.xy())
            .wh(self.rect.wh())
            .rgb(0.1, 0.1, 0.1);
    }
}

impl Mover {
    fn new(m: f32, x: f32, y: f32) -> Self {
        // Mass is tied to size
        let mass = m;
        let position = pt2(x, y);
        let velocity = vec2(0.0, 0.0);
        let acceleration = vec2(0.0, 0.0);
        Mover {
            position,
            velocity,
            acceleration,
            mass,
        }
    }

    fn new_random(rect: &Rect) -> Self {
        Mover::new(
            random_range(0.5f32, 4.0),
            random_range(rect.left(), rect.right()),
            rect.top(),
        )
    }

    // Newton's 2nd law: F = M * A
    // or A = F / M
    fn apply_force(&mut self, force: Vector2) {
        // Divide by mass
        let f = force / self.mass;
        // Accumulate all forces in acceleration
        self.acceleration += f;
    }

    fn update(&mut self) {
        // Velocity changes according to acceleration
        self.velocity += self.acceleration;
        // Position changes by velocity
        self.position += self.velocity;
        // We must clear acceleration each frame
        self.acceleration *= 0.0;
    }

    // Draw Mover
    fn display(&self, draw: &app::Draw) {
        draw.ellipse()
            .xy(self.position)
            .w_h(self.mass * 16.0, self.mass * 16.0)
            .rgba(0.0, 0.0, 0.0, 0.5);
    }

    // Bounce off bottom of window
    fn check_edges(&mut self, rect: Rect) {
        if self.position.y < rect.bottom() {
            self.velocity.y *= -0.9; // A little dampening when hitting the bottom
            self.position.y = rect.bottom();
        }
    }
}

fn model(app: &App) -> Model {
    let rect = Rect::from_w_h(640.0, 360.0);
    app.new_window()
        .with_dimensions(rect.w() as u32, rect.h() as u32)
        .mouse_pressed(mouse_pressed)
        .view(view)
        .build()
        .unwrap();

    // Nine moving bodies
    let movers = (0..9)
        .map(|_| {
            Mover::new_random(&app.window_rect())
        })
        .collect();

    // Create an instance of our Liquid type
    let rect = Rect::from_w_h(rect.w(), rect.h() * 0.5).align_bottom_of(rect);
    let liquid = Liquid::new(rect, 0.1);

    Model { movers, liquid }
}

fn mouse_pressed(app: &App, m: &mut Model, _button: MouseButton) {
    // Restart all the Mover objects randomly
    for mover in &mut m.movers {
        *mover = Mover::new_random(&app.window_rect());
    }
}

fn update(app: &App, m: &mut Model, _update: Update) {
    for i in 0..m.movers.len() {
        // Is the Mover in the liquid?
        if m.liquid.contains(&m.movers[i]) {
            let drag_force = m.liquid.drag(&m.movers[i]);
            // Apply drag force to Mover
            m.movers[i].apply_force(drag_force);
        }

        // Gravity is scaled by mass here!
        let gravity = vec2(0.0, -0.1 * m.movers[i].mass);

        // Apply gravity
        m.movers[i].apply_force(gravity);
        m.movers[i].update();
        m.movers[i].check_edges(app.window_rect());
    }
}

fn view(app: &App, m: &Model, frame: Frame) -> Frame {
    // Begin drawing
    let draw = app.draw();
    draw.background().color(WHITE);

    // Draw water
    m.liquid.display(&draw);

    // Draw movers
    for mover in &m.movers {
        mover.display(&draw);
    }

    // Write the result of our drawing to the window's OpenGL frame.
    draw.to_frame(app, &frame).unwrap();

    // Return the drawn frame.
    frame
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use std::collections::BTreeMap;
use std::cmp::{max, min, Ordering};
use interpreter::InterpretResult;
use variable::Variable;

/// Handles the dispatching of named functions using an array of arguments.
pub trait FnDispatcher {
    /// Dispatches and interprets a function by name.
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>) -> InterpretResult;
}

/// Built-in function implementations.
#[derive(Clone)]
pub struct BuiltinFunctions;

impl BuiltinFunctions {
    /// Creates a new Builtins function dispatcher.
    pub fn new() -> BuiltinFunctions {
        BuiltinFunctions
    }
}

/// Validates the arity of a function.
#[inline]
fn arity(fn_name: &str, arity: usize, args: &Vec<Rc<Variable>>) -> Result<(), String> {
    if args.len() != arity {
        Err(format!("{} arity error: expected {} args, found {}", fn_name, arity, args.len()))
    } else {
        Ok(())
    }
}

fn homogeneous_array(valid_types: Vec<&str>, array: &Vec<Rc<Variable>>) -> bool {
    let matched_type = array[0].get_type();
    if !valid_types.contains(&matched_type) {
        return false;
    }
    for a in array {
        if a.get_type() != matched_type {
            return false;
        }
    }
    return true;
}

/// Macro used to format a type error.
macro_rules! type_err {
    ($f:expr, $position:expr, $expected:expr, $given:expr) => {
        format!("{} expects arg {} to be {}. Given {:?}", $f, $position, $expected, $given)
    }
}

/// Macro used to variadically validate validate Variable and argument arity.
macro_rules! validate {
    // Validate positional arguments only.
    ($name:expr, $args:expr, $($x:expr),*) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            try!(arity($name, validators.len(), $args));
            for (k, v) in $args.iter().enumerate() {
                if let Err(e) = validators[k](v) {
                    return Err(format!("{} error at argument {}: {}", $name, k, e));
                }
            }
        }
    );
    // Validate positional arguments with a variadic validator.
    ($name:expr, $args:expr, $($x:expr),* ...$variadic:expr ) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            if $args.len() < validators.len() {
                return Err(format!("{} arity error: expected at least {} args, found {}",
                                   $name, validators.len(), $args.len()));
            }
            for (k, v) in $args.iter().enumerate() {
                try!((match validators.get(k) {
                    Some(validator) => validator(v),
                    None => $variadic(v)
                }).or_else(|e| Err(format!("{} error at argument {}: {}", $name, k, e))));
            }
        }
    );
}

macro_rules! homogeneous {
    ($($x:ident)|*) => [
        Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
            let valid_types = vec![$(stringify!($x)), *];
            match **arg {
                Variable::Array(ref array) if array.is_empty() => Ok(()),
                Variable::Array(ref array) if homogeneous_array(valid_types, array) => Ok(()),
                _ => Err(format!("type array[{}]", valid_types.join("|")))
            }
        })
    ];
}

/// Creates a closure used to validate the type of the given variable.
macro_rules! jptype {
    // Validate a type against a single acceptable type.
    ($type_name:ident) => [
        Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
            let arg_type = arg.get_type();
            if arg_type != "any" && arg_type != stringify!($type_name) {
                Err(format!("type {}", stringify!($type_name)))
            } else {
                Ok(())
            }
        })
    ];
    // Validate a type against multiple acceptable types
    ($($x:ident)|*) => [
        {
            Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
                let valid_types = vec![$(stringify!($x)), *];
                let arg_type = arg.get_type();
                if arg_type != "any" && !valid_types.contains(&arg_type) {
                    Err(format!("type {}", valid_types.join("|")))
                } else {
                    Ok(())
                }
            })
        }
    ];
}

/// Macro used to implement min and max functions.
macro_rules! min_max {
    ($operator:ident, $args:expr) => (
        match *$args[0] {
            Variable::Array(ref array) if array.is_empty() => Ok(Rc::new(Variable::Null)),
            Variable::Array(ref array) => {
                if array[0].is_string() {
                    Ok(Rc::new(Variable::String(array.iter().fold(
                        array[0].as_string().unwrap().clone(),
                        |acc, item| $operator(acc, item.as_string().unwrap().clone())))))
                } else {
                    Ok(Rc::new(Variable::F64(array.iter().fold(
                        array[0].as_f64().unwrap(),
                        |acc, item| acc.$operator(item.as_f64().unwrap())))))
                }
            },
            _ => panic!() // never encountered due to previous validation
        }
    )
}

impl FnDispatcher for BuiltinFunctions {
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>) -> InterpretResult {
        match fn_name {
            "abs" => {
                validate!("abs", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().abs())))
            },
            "avg" => {
                try!(arity("avg", 1, args));
                args[0].as_array()
                    .and_then(|array| {
                        let mut total = 0f64;
                        for value in array {
                            match **value {
                                Variable::I64(n) => total += n as f64,
                                Variable::U64(n) => total += n as f64,
                                Variable::F64(n) => total += n,
                                _ => return None
                            }
                        }
                        Some(Rc::new(Variable::F64(total / array.len() as f64)))
                    })
                    .ok_or(type_err!("avg", 0, "array[number]", args[0]))
            },
            "ceil" => {
                validate!("ceil", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().ceil())))
            },
            "contains" => {
                validate!("contains", args, jptype![array|string], jptype![any]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::Boolean(a.contains(&args[1])))),
                    Variable::String(ref subj) => {
                        match args[1].as_string() {
                            Some(search) => Ok(Rc::new(Variable::Boolean(subj.contains(search)))),
                            None => Err(format!("contains found {:?} for string search arg",
                                                args[1]))
                        }
                    },
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "ends_with" => {
                validate!("ends_with", args, jptype![string], jptype![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.ends_with(search))))
            },
            "floor" => {
                validate!("floor", args, jptype![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().floor())))
            },
            "join" => {
                validate!("join", args, jptype![string], homogeneous![string]);
                Ok(Rc::new(Variable::String(args.iter().skip(1)
                    .map(|ref v| v.as_string().unwrap().clone())
                    .collect::<Vec<String>>()
                    .join(args[0].as_string().unwrap()))))
            },
            "keys" => {
                validate!("keys", args, jptype![object]);
                Ok(Rc::new(args[0].object_keys_to_array().unwrap()))
            },
            "length" => {
                validate!("length", args, jptype![array|object|string]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::U64(a.len() as u64))),
                    Variable::Object(ref m) => Ok(Rc::new(Variable::U64(m.len() as u64))),
                    Variable::String(ref s) => Ok(Rc::new(Variable::U64(s.len() as u64))),
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "max" => {
                validate!("max", args, homogeneous![string|number]);
                min_max!(max, args)
            },
            "merge" => {
                validate!("merge", args, jptype![object] ...jptype![object]);
                let mut result = args[0].as_object().unwrap().clone();
                for arg in args.iter().skip(1) {
                    result.extend(arg.as_object().unwrap().clone());
                }
                Ok(Rc::new(Variable::Object(result)))
            },
            "min" => {
                validate!("min", args, homogeneous![string|number]);
                min_max!(min, args)
            },
            "not_null" => {
                validate!("not_null", args, jptype![any] ...jptype![any]);
                for arg in args {
                    if **arg != Variable::Null {
                        return Ok(arg.clone());
                    }
                }
                Ok(Rc::new(Variable::Null))
            },
            "reverse" => {
                validate!("reverse", args, jptype![array]);
                let mut values = args.clone();
                values.reverse();
                Ok(Rc::new(Variable::Array(values)))
            },
            "sort" => {
                validate!("sort", args, homogeneous![string|number]);
                let mut values: Vec<Rc<Variable>> = args[0].as_array().unwrap().clone();
                if values[0].is_string() {
                    values.sort_by(|a, b| a.as_string().unwrap().cmp(b.as_string().unwrap()));
                } else {
                    values.sort_by(|a, b| a.as_f64().unwrap()
                        .partial_cmp(&b.as_f64().unwrap())
                        .unwrap_or(Ordering::Equal));
                }
                Ok(Rc::new(Variable::Array(values)))
            },
            "starts_with" => {
                validate!("starts_with", args, jptype![string], jptype![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.starts_with(search))))
            },
            "sum" => {
                validate!("sum", args, homogeneous![number]);
                let array = args[0].as_array().unwrap();
                Ok(Rc::new(Variable::F64(array.iter().fold(
                    array[0].as_f64().unwrap().clone(),
                    |acc, item| acc.max(item.as_f64().unwrap())))))
            },
            "to_array" => {
                try!(arity("to_array", 1, args));
                match *args[0] {
                    Variable::Array(_) => Ok(args[0].clone()),
                    _ => Ok(Rc::new(Variable::Array(vec![args[0].clone()])))
                }
            },
            "to_number" => {
                try!(arity("to_number", 1, args));
                match *args[0] {
                    Variable::I64(_) | Variable::F64(_) | Variable::U64(_) => Ok(args[0].clone()),
                    Variable::String(ref s) => {
                        match s.parse::<f64>() {
                            Ok(f)  => Ok(Rc::new(Variable::F64(f))),
                            Err(_) => Ok(Rc::new(Variable::Null))
                        }
                    },
                    _ => Ok(Rc::new(Variable::Null))
                }
            },
            "to_string" => {
                validate!("to_string", args, jptype![object|array|boolean|number|string|null]);
                Ok(Rc::new(Variable::String(args[0].to_string().unwrap())))
            },
            "type" => {
                try!(arity("type", 1, args));
                Ok(Rc::new(Variable::String(args[0].get_type().to_string())))
            },
            "values" => {
                validate!("values", args, jptype![object]);
                Ok(Rc::new(args[0].object_values_to_array().unwrap()))
            },
            _ => Err(format!("Unknown function: {}", fn_name))
        }
    }
}
<commit_msg>Cleaning up macros and avg fn<commit_after>use std::rc::Rc;

use std::cmp::{max, min, Ordering};
use interpreter::InterpretResult;
use variable::Variable;

/// Handles the dispatching of named functions using an array of arguments.
pub trait FnDispatcher {
    /// Dispatches and interprets a function by name.
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>) -> InterpretResult;
}

/// Built-in function implementations.
#[derive(Clone)]
pub struct BuiltinFunctions;

impl BuiltinFunctions {
    /// Creates a new Builtins function dispatcher.
    pub fn new() -> BuiltinFunctions {
        BuiltinFunctions
    }
}

/// Validates the arity of a function.
#[inline]
fn arity(fn_name: &str, arity: usize, args: &Vec<Rc<Variable>>) -> Result<(), String> {
    if args.len() != arity {
        Err(format!("{} arity error: expected {} args, found {}", fn_name, arity, args.len()))
    } else {
        Ok(())
    }
}

/// Validates that an array contains only a single allowed type.
#[inline]
fn homogeneous_array(valid_types: Vec<&str>, array: &Vec<Rc<Variable>>) -> bool {
    let matched_type = array[0].get_type();
    if !valid_types.contains(&matched_type) {
        return false;
    }
    for a in array {
        if a.get_type() != matched_type {
            return false;
        }
    }
    return true;
}

/// Macro used to variadically validate validate Variable and argument arity.
macro_rules! validate {
    // Validate positional arguments only.
    ($name:expr, $args:expr, $($x:expr),*) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            try!(arity($name, validators.len(), $args));
            for (k, v) in $args.iter().enumerate() {
                if let Err(e) = validators[k](v) {
                    return Err(format!("{} error at argument {}: {}", $name, k, e));
                }
            }
        }
    );
    // Validate positional arguments with a variadic validator.
    ($name:expr, $args:expr, $($x:expr),* ...$variadic:expr ) => (
        {
            let validators: Vec<Box<Fn(&Rc<Variable>) -> Result<(), String>>> = vec![$($x), *];
            if $args.len() < validators.len() {
                return Err(format!("{} arity error: expected at least {} args, found {}",
                                   $name, validators.len(), $args.len()));
            }
            for (k, v) in $args.iter().enumerate() {
                try!((match validators.get(k) {
                    Some(validator) => validator(v),
                    None => $variadic(v)
                }).or_else(|e| Err(format!("{} error at argument {}: {}", $name, k, e))));
            }
        }
    );
}

/// Validates that a vector contains a homogeneous array of a specific type(s).
macro_rules! array {
    ($($x:ident)|*) => [
        Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
            let valid_types = vec![$(stringify!($x)), *];
            match **arg {
                Variable::Array(ref array) if array.is_empty() => Ok(()),
                Variable::Array(ref array) if homogeneous_array(valid_types, array) => Ok(()),
                _ => Err(format!("type array[{}]", valid_types.join("|")))
            }
        })
    ];
}

/// Creates a closure used to validate the type of the given variable.
macro_rules! types {
    ($($x:ident)|*) => [
        {
            Box::new(move |arg: &Rc<Variable>| -> Result<(), String> {
                let valid_types = vec![$(stringify!($x)), *];
                let arg_type = arg.get_type();
                if arg_type == "any" || valid_types.contains(&arg_type) {
                    Ok(())
                } else {
                    Err(format!("type {}", valid_types.join("|")))
                }
            })
        }
    ];
}

/// Macro used to implement min and max functions.
macro_rules! min_max {
    ($operator:ident, $args:expr) => (
        match *$args[0] {
            Variable::Array(ref array) if array.is_empty() => Ok(Rc::new(Variable::Null)),
            Variable::Array(ref array) => {
                if array[0].is_string() {
                    Ok(Rc::new(Variable::String(array.iter().fold(
                        array[0].as_string().unwrap().clone(),
                        |acc, item| $operator(acc, item.as_string().unwrap().clone())))))
                } else {
                    Ok(Rc::new(Variable::F64(array.iter().fold(
                        array[0].as_f64().unwrap(),
                        |acc, item| acc.$operator(item.as_f64().unwrap())))))
                }
            },
            _ => panic!() // never encountered due to previous validation
        }
    )
}

impl FnDispatcher for BuiltinFunctions {
    fn call(&self, fn_name: &str, args: &Vec<Rc<Variable>>) -> InterpretResult {
        match fn_name {
            "abs" => {
                validate!("abs", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().abs())))
            },
            "avg" => {
                validate!("avg", args, array!(number));
                let array = args[0].as_array().unwrap();
                let sum = array.iter().fold(0f64, |a, ref b| a + b.as_f64().unwrap());
                Ok(Rc::new(Variable::F64(sum / (array.len() as f64))))
            },
            "ceil" => {
                validate!("ceil", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().ceil())))
            },
            "contains" => {
                validate!("contains", args, types![array|string], types![any]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::Boolean(a.contains(&args[1])))),
                    Variable::String(ref subj) => {
                        match args[1].as_string() {
                            Some(search) => Ok(Rc::new(Variable::Boolean(subj.contains(search)))),
                            None => Err(format!("contains found {:?} for string search arg",
                                                args[1]))
                        }
                    },
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "ends_with" => {
                validate!("ends_with", args, types![string], types![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.ends_with(search))))
            },
            "floor" => {
                validate!("floor", args, types![number]);
                Ok(Rc::new(Variable::F64(args[0].as_f64().unwrap().floor())))
            },
            "join" => {
                validate!("join", args, types![string], array![string]);
                Ok(Rc::new(Variable::String(args.iter().skip(1)
                    .map(|ref v| v.as_string().unwrap().clone())
                    .collect::<Vec<String>>()
                    .join(args[0].as_string().unwrap()))))
            },
            "keys" => {
                validate!("keys", args, types![object]);
                Ok(Rc::new(args[0].object_keys_to_array().unwrap()))
            },
            "length" => {
                validate!("length", args, types![array|object|string]);
                match *args[0] {
                    Variable::Array(ref a) => Ok(Rc::new(Variable::U64(a.len() as u64))),
                    Variable::Object(ref m) => Ok(Rc::new(Variable::U64(m.len() as u64))),
                    Variable::String(ref s) => Ok(Rc::new(Variable::U64(s.len() as u64))),
                    _ => panic!() // never encountered due to previous validation
                }
            },
            "max" => {
                validate!("max", args, array![string|number]);
                min_max!(max, args)
            },
            "merge" => {
                validate!("merge", args, types![object] ...types![object]);
                let mut result = args[0].as_object().unwrap().clone();
                for arg in args.iter().skip(1) {
                    result.extend(arg.as_object().unwrap().clone());
                }
                Ok(Rc::new(Variable::Object(result)))
            },
            "min" => {
                validate!("min", args, array![string|number]);
                min_max!(min, args)
            },
            "not_null" => {
                validate!("not_null", args, types![any] ...types![any]);
                for arg in args {
                    if **arg != Variable::Null {
                        return Ok(arg.clone());
                    }
                }
                Ok(Rc::new(Variable::Null))
            },
            "reverse" => {
                validate!("reverse", args, types![array]);
                let mut values = args.clone();
                values.reverse();
                Ok(Rc::new(Variable::Array(values)))
            },
            "sort" => {
                validate!("sort", args, array![string|number]);
                let mut values: Vec<Rc<Variable>> = args[0].as_array().unwrap().clone();
                if values[0].is_string() {
                    values.sort_by(|a, b| a.as_string().unwrap().cmp(b.as_string().unwrap()));
                } else {
                    values.sort_by(|a, b| a.as_f64().unwrap()
                        .partial_cmp(&b.as_f64().unwrap())
                        .unwrap_or(Ordering::Equal));
                }
                Ok(Rc::new(Variable::Array(values)))
            },
            "starts_with" => {
                validate!("starts_with", args, types![string], types![string]);
                let subject = args[0].as_string().unwrap();
                let search = args[1].as_string().unwrap();
                Ok(Rc::new(Variable::Boolean(subject.starts_with(search))))
            },
            "sum" => {
                validate!("sum", args, array![number]);
                let array = args[0].as_array().unwrap();
                Ok(Rc::new(Variable::F64(array.iter().fold(
                    array[0].as_f64().unwrap().clone(),
                    |acc, item| acc.max(item.as_f64().unwrap())))))
            },
            "to_array" => {
                try!(arity("to_array", 1, args));
                match *args[0] {
                    Variable::Array(_) => Ok(args[0].clone()),
                    _ => Ok(Rc::new(Variable::Array(vec![args[0].clone()])))
                }
            },
            "to_number" => {
                try!(arity("to_number", 1, args));
                match *args[0] {
                    Variable::I64(_) | Variable::F64(_) | Variable::U64(_) => Ok(args[0].clone()),
                    Variable::String(ref s) => {
                        match s.parse::<f64>() {
                            Ok(f)  => Ok(Rc::new(Variable::F64(f))),
                            Err(_) => Ok(Rc::new(Variable::Null))
                        }
                    },
                    _ => Ok(Rc::new(Variable::Null))
                }
            },
            "to_string" => {
                validate!("to_string", args, types![object|array|boolean|number|string|null]);
                Ok(Rc::new(Variable::String(args[0].to_string().unwrap())))
            },
            "type" => {
                try!(arity("type", 1, args));
                Ok(Rc::new(Variable::String(args[0].get_type().to_string())))
            },
            "values" => {
                validate!("values", args, types![object]);
                Ok(Rc::new(args[0].object_values_to_array().unwrap()))
            },
            _ => Err(format!("Unknown function: {}", fn_name))
        }
    }
}
<|endoftext|>


<commit_before>use std::str::raw;
use std::libc::c_char;

pub struct Proj {
    c_proj: *(),
}

#[link(name="proj")]
extern {
    fn pj_init_plus(definition: *c_char) -> *();
    fn pj_free(pj: *());
    fn pj_get_def(pj: *()) -> *c_char;
}

impl Proj {
    pub fn new(definition: &str) -> Option<Proj> {
        let c_proj = definition.with_c_str(|c_definition| {
            unsafe { return pj_init_plus(c_definition) }
        });
        return match c_proj.is_null() {
            true  => None,
            false => Some(Proj{c_proj: c_proj}),
        };
    }

    pub fn get_def(&self) -> ~str {
        unsafe {
            let rv = pj_get_def(self.c_proj);
            return raw::from_c_str(rv);
        }
    }
}

impl Drop for Proj {
    fn drop(&mut self) {
        unsafe { pj_free(self.c_proj); }
    }
}

#[test]
fn test_new_projection() {
    let wgs84 = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs";
    let proj = Proj::new(wgs84).unwrap();
    assert_eq!(
        proj.get_def(),
        ~" +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0");
}
<commit_msg>project coordinate pair<commit_after>use std::str::raw;
use std::libc::{c_int, c_char, c_long, c_double};

pub struct Proj {
    c_proj: *(),
}

//static DEG_TO_RAD: f64 = 0.017453292519943295769236907684886;

#[link(name="proj")]
extern {
    fn pj_init_plus(definition: *c_char) -> *();
    fn pj_free(pj: *());
    fn pj_get_def(pj: *()) -> *c_char;
    fn pj_transform(
        srcdefn: *(),
        dstdefn: *(),
        point_count: c_long,
        point_offset: c_int,
        x: *mut c_double,
        y: *mut c_double,
        z: *mut c_double
    ) -> c_int;
    fn pj_strerrno(code: c_int) -> *c_char;
}

fn error_message(code: c_int) -> ~str {
    unsafe {
        let rv = pj_strerrno(code);
        return raw::from_c_str(rv);
    }
}

impl Proj {
    pub fn new(definition: &str) -> Option<Proj> {
        let c_proj = definition.with_c_str(|c_definition| {
            unsafe { return pj_init_plus(c_definition) }
        });
        return match c_proj.is_null() {
            true  => None,
            false => Some(Proj{c_proj: c_proj}),
        };
    }

    pub fn get_def(&self) -> ~str {
        unsafe {
            let rv = pj_get_def(self.c_proj);
            return raw::from_c_str(rv);
        }
    }

    pub fn project(&self, target: &Proj, x: f64, y: f64) -> (f64, f64) {
        let mut c_x: c_double = x;
        let mut c_y: c_double = y;
        let mut c_z: c_double = 0.;
        unsafe {
            let rv = pj_transform(
                self.c_proj,
                target.c_proj,
                1,
                1,
                &mut c_x,
                &mut c_y,
                &mut c_z
            );
            //if rv != 0 {
            //    println!("{}", error_message(rv));
            //}
            assert!(rv == 0);
        }
        return (c_x, c_y);
    }
}

impl Drop for Proj {
    fn drop(&mut self) {
        unsafe { pj_free(self.c_proj); }
    }
}

#[test]
fn test_new_projection() {
    let wgs84 = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs";
    let proj = Proj::new(wgs84).unwrap();
    assert_eq!(
        proj.get_def(),
        ~" +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0");
}

fn assert_almost_eq(a: f64, b: f64) {
    let f: f64 = a / b;
    assert!(f < 1.00001);
    assert!(f > 0.99999);
}

#[test]
fn test_transform() {
    let wgs84 = Proj::new("+proj=longlat +datum=WGS84 +no_defs").unwrap();
    let stereo70 = Proj::new(
        "+proj=sterea +lat_0=46 +lon_0=25 +k=0.99975 " +
        "+x_0=500000 +y_0=500000 +ellps=krass +units=m +no_defs"
        ).unwrap();

    let (lng, lat) = stereo70.project(&wgs84, 500000., 500000.);
    assert_almost_eq(lng, 0.436332);
    assert_almost_eq(lat, 0.802851);

    let (x, y) = wgs84.project(&stereo70, 0.436332, 0.802851);
    assert_almost_eq(x, 500000.);
    assert_almost_eq(y, 500000.);
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS x86_64 bootstrap
//!
//! This crate contains code for the 32-bit protected mode boot routine for
//! x86_64 CPUs. When we boot up an x86_64 system using GRUB & multiboot, we
//! end up with the CPU running in 32-bit 'protected mode', rather than 64-bit
//! 'long mode'. Before we can jump into long mode, we have to perform a
//! handful of setup tasks in protected mode.
//!
//! This boot routine lives in a separate crate, with a 32-bit `target.json`.
//! When building SOS for x86_64, we have to compile this crate separately and
//! then link the resulting 32-bit object with the rest of the 64-bit kernel
//! object.
//!
//! This boot crate is only necessary for x86_64. For other architectures, all
//! boot code can live in the main kernel crate.
//!
//! For more information, refer to:
//! + the [intermezzOS book]
//! + the [OSDev Wiki] article on long mode
//! + Philipp Oppermann's [blog post]
//!
//! [intermezzOS book]: http://intermezzos.github.io/book/transitioning-to-long-mode.html
//! [OSDev Wiki]: http://wiki.osdev.org/Long_Mode#Long_Mode
//! [blog post]: http://os.phil-opp.com/entering-longmode.html

#![crate_name = "boot"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(linkage)]
#![feature(struct_field_attributes)]
#![feature(stmt_expr_attributes)]
#![no_std]

extern crate rlibc;

const TABLE_LENGTH: usize = 512;
/// The size of a "huge" page
const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB
/// Page table entry flags for a page that is present and writable.
const ENTRY_FLAGS_PW: u64 = 0b11;

/// A page table is an array of page table entries.
type Table = [TableEntry; TABLE_LENGTH];

trait PageTable: Sized {
    /// Install this page table as the top-level page table.
    #[inline(always)]
    unsafe fn set_top_level(&'static self) {
        asm!("mov cr3, $0" :: "r"(self) :: "intel");
    }
}

impl PageTable for Table { }

/// A page table entry is a 64-bit unsigned integer.
///
/// We represent this as a [newtype] rather than a type alias, because we want
/// to implement specific functionality on it.
///
/// [newtype]: https://aturon.github.io/features/types/newtype.html
#[repr(C)]
struct TableEntry(u64);

impl TableEntry {
    /// Set this table entry to map to a lower-level page table.
    // TODO: use a marker type to ensure this always maps to a _lower-level_
    //       table?
    #[inline(always)]
    unsafe fn map_to_table(&mut self, to: &'static Table) {
        *self = TableEntry(to as *const _ as u64 | ENTRY_FLAGS_PW);
    }

    /// Set this table entry to map to a huge page with the given number.
    #[inline(always)]
    unsafe fn map_to_page(&mut self, number: usize) {
        // Page table entry flags for a page that is huge, present, and writable.
        const ENTRY_FLAGS_HUGE: u64 = 0b10000011;
        // the start address is the page number times the page's size
        let addr = number as u64 * HUGE_PAGE_SIZE;
        *self = TableEntry(addr | ENTRY_FLAGS_HUGE);
    }

}

use core::convert;

macro_rules! set_flags {
    (%$register:ident $( |= $body:expr);+ ) => {
        let mut $register: usize;
        asm!( concat!("mov $0, ", stringify!($register))
            : "=r"($register)
            ::: "intel");
        $($register |= $body;)+
        asm!( concat!("mov ", stringify!($register), ", $0")
            :: "r"($register)
            :: "intel");
    }
}

#[repr(C, packed)]
pub struct Gdt { _null: u64
               , code: u64
               }

#[repr(C, packed)]
pub struct GdtPointer { /// the length of the GDT
                        pub limit: u16
                      , /// pointer to the GDT
                        pub base: &'static Gdt
                      }

impl GdtPointer {
    #[cold] #[inline(always)]
    unsafe fn load (&self) {
        asm!("lgdt ($0)" :: "r"(self) : "memory");
    }
}

impl convert::From<&'static Gdt> for GdtPointer {
    #[cold] #[inline(always)]
    fn from(gdt: &'static Gdt) -> Self {
        use core::mem::size_of_val;
        GdtPointer { limit: size_of_val(gdt) as u16 - 1
                   , base: gdt }
    }
}

#[link_name = ".gdt64"]
#[link_section = ".gdt"]
#[no_mangle]
pub static GDT: Gdt
    = Gdt { _null: 0
          , code: (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
          };

#[inline(always)]
fn boot_write(s: &[u8]) {
    unsafe {
        use core::ptr::write_volatile;
        let vga_buf = 0xb8000 as *mut u16;
    	for (n, c) in s.iter().enumerate() {
    		write_volatile(vga_buf.offset(n as isize), 0x0200 + *c as u16);
    	}

    }

}

extern "C" {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;
}

#[cold]
#[inline(always)]
#[naked]
unsafe fn create_page_tables() {
    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511].map_to_table(&pml4_table);
    // map first PML4 entry to PDP table
    pml4_table[0].map_to_table(&pdp_table);
    // map first PDPT entry to PD table
    pdp_table[0].map_to_table(&pd_table);

    boot_write(b"3.1");

    //-- map the PD table ----------------------------------------------------
    for (page_number, entry) in pd_table.iter_mut().enumerate() {
        entry.map_to_page(page_number);
    }

    boot_write(b"3.2");
}

#[cold]
#[inline(always)]
unsafe fn set_long_mode() {
    // load PML4 addr to cr3
    &pml4_table.set_top_level();
    boot_write(b"3.3");

    // // enable PAE flag in cr4
    set_flags!(%cr4 |= 1 << 5 );
    boot_write(b"3.4");

    // set the long mode bit in EFER MSR (model specific register)
    asm!( "mov   ecx, 0xC0000080
           rdmsr
           or    eax, 1 << 8
           wrmsr"
        :::: "intel");
    boot_write(b"3.5");

    // enable paging in cr0
    set_flags!(%cr0 |= 1 << 31;
                    |= 1 << 16 );
    boot_write(b"3.6")
}

/// Test whether or not this system supports Multiboot 2
#[cold]
#[inline(always)]
unsafe fn is_multiboot_supported() -> bool {
    const MULTIBOOT_MAGIC: usize = 0x36d76289;
    let eax: usize;
    asm!("mov eax, $0" : "=r"(eax) ::: "intel");
    eax == MULTIBOOT_MAGIC
}

#[cold]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() {
    boot_write(b"0");
    asm!("cli");

    // 1. Move Multiboot info pointer to edi
    asm!("mov edi, ebx" :::: "intel");
    boot_write(b"1");

    // 2. make sure the system supports SOS
    // TODO: port this from boot.asm
    if !is_multiboot_supported() {
        loop { boot_write(b"ERROR: multiboot not supported!"); }
    }
    boot_write(b"2");

    // 3. if everything is okay, create the page tables and start long mode
    create_page_tables();
    set_long_mode();

    // 4. load the 64-bit GDT
    GdtPointer::from(&GDT).load();
    boot_write(b"4");

    // 6. jump to the 64-bit boot subroutine.
    asm!("ljmpl $$8, $$long_mode_init");

}
<commit_msg>fix(boot): temporarily remove uses of `set_flags!` macro<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS x86_64 bootstrap
//!
//! This crate contains code for the 32-bit protected mode boot routine for
//! x86_64 CPUs. When we boot up an x86_64 system using GRUB & multiboot, we
//! end up with the CPU running in 32-bit 'protected mode', rather than 64-bit
//! 'long mode'. Before we can jump into long mode, we have to perform a
//! handful of setup tasks in protected mode.
//!
//! This boot routine lives in a separate crate, with a 32-bit `target.json`.
//! When building SOS for x86_64, we have to compile this crate separately and
//! then link the resulting 32-bit object with the rest of the 64-bit kernel
//! object.
//!
//! This boot crate is only necessary for x86_64. For other architectures, all
//! boot code can live in the main kernel crate.
//!
//! For more information, refer to:
//! + the [intermezzOS book]
//! + the [OSDev Wiki] article on long mode
//! + Philipp Oppermann's [blog post]
//!
//! [intermezzOS book]: http://intermezzos.github.io/book/transitioning-to-long-mode.html
//! [OSDev Wiki]: http://wiki.osdev.org/Long_Mode#Long_Mode
//! [blog post]: http://os.phil-opp.com/entering-longmode.html

#![crate_name = "boot"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![feature(linkage)]
#![feature(struct_field_attributes)]
#![feature(stmt_expr_attributes)]
#![no_std]

extern crate rlibc;

const TABLE_LENGTH: usize = 512;
/// The size of a "huge" page
const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB
/// Page table entry flags for a page that is present and writable.
const ENTRY_FLAGS_PW: u64 = 0b11;

/// A page table is an array of page table entries.
type Table = [TableEntry; TABLE_LENGTH];

trait PageTable: Sized {
    /// Install this page table as the top-level page table.
    #[inline(always)]
    unsafe fn set_top_level(&'static self) {
        asm!("mov cr3, $0" :: "r"(self) :: "intel");
    }
}

impl PageTable for Table { }

/// A page table entry is a 64-bit unsigned integer.
///
/// We represent this as a [newtype] rather than a type alias, because we want
/// to implement specific functionality on it.
///
/// [newtype]: https://aturon.github.io/features/types/newtype.html
#[repr(C)]
struct TableEntry(u64);

impl TableEntry {
    /// Set this table entry to map to a lower-level page table.
    // TODO: use a marker type to ensure this always maps to a _lower-level_
    //       table?
    #[inline(always)]
    unsafe fn map_to_table(&mut self, to: &'static Table) {
        *self = TableEntry(to as *const _ as u64 | ENTRY_FLAGS_PW);
    }

    /// Set this table entry to map to a huge page with the given number.
    #[inline(always)]
    unsafe fn map_to_page(&mut self, number: usize) {
        // Page table entry flags for a page that is huge, present, and writable.
        const ENTRY_FLAGS_HUGE: u64 = 0b10000011;
        // the start address is the page number times the page's size
        let addr = number as u64 * HUGE_PAGE_SIZE;
        *self = TableEntry(addr | ENTRY_FLAGS_HUGE);
    }

}

use core::convert;

macro_rules! set_flags {
    (%$register:ident $( |= $body:expr);+ ) => {
        let mut $register: usize;
        asm!( concat!("mov $0, ", stringify!($register))
            : "=r"($register)
            ::: "intel");
        $($register |= $body;)+
        asm!( concat!("mov ", stringify!($register), ", $0")
            :: "r"($register)
            :: "intel");
    }
}

#[repr(C, packed)]
pub struct Gdt { _null: u64
               , code: u64
               }

#[repr(C, packed)]
pub struct GdtPointer { /// the length of the GDT
                        pub limit: u16
                      , /// pointer to the GDT
                        pub base: &'static Gdt
                      }

impl GdtPointer {
    #[cold] #[inline(always)]
    unsafe fn load (&self) {
        asm!("lgdt ($0)" :: "r"(self) : "memory");
    }
}

impl convert::From<&'static Gdt> for GdtPointer {
    #[cold] #[inline(always)]
    fn from(gdt: &'static Gdt) -> Self {
        use core::mem::size_of_val;
        GdtPointer { limit: size_of_val(gdt) as u16 - 1
                   , base: gdt }
    }
}

#[link_name = ".gdt64"]
#[link_section = ".gdt"]
#[no_mangle]
pub static GDT: Gdt
    = Gdt { _null: 0
          , code: (1<<44) | (1<<47) | (1<<41) | (1<<43) | (1<<53)
          };

#[inline(always)]
fn boot_write(s: &[u8]) {
    unsafe {
        use core::ptr::write_volatile;
        let vga_buf = 0xb8000 as *mut u16;
    	for (n, c) in s.iter().enumerate() {
    		write_volatile(vga_buf.offset(n as isize), 0x0200 + *c as u16);
    	}

    }

}

extern "C" {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;
}

#[cold]
#[inline(always)]
#[naked]
unsafe fn create_page_tables() {
    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511].map_to_table(&pml4_table);
    // map first PML4 entry to PDP table
    pml4_table[0].map_to_table(&pdp_table);
    // map first PDPT entry to PD table
    pdp_table[0].map_to_table(&pd_table);

    boot_write(b"3.1");

    //-- map the PD table ----------------------------------------------------
    for (page_number, entry) in pd_table.iter_mut().enumerate() {
        entry.map_to_page(page_number);
    }

    boot_write(b"3.2");
}

#[cold]
#[inline(always)]
unsafe fn set_long_mode() {
    // load PML4 addr to cr3
    &pml4_table.set_top_level();
    boot_write(b"3.3");

    // // enable PAE flag in cr4
    // set_flags!(%cr4 |= 1 << 5 );
    asm!("mov eax, cr4
          or eax, 1 << 5
          mov cr4, eax" ::: "memory" : "intel", "volatile");
    boot_write(b"3.4");

    // set the long mode bit in EFER MSR (model specific register)
    asm!( "mov   ecx, 0xC0000080
           rdmsr
           or    eax, 1 << 8
           wrmsr"
        :::"memory": "intel", "volatile");
    boot_write(b"3.5");

    // enable paging in cr0
    // set_flags!(%cr0 |= 1 << 31;
    //                 |= 1 << 16 );

    asm!("mov eax, cr0
          or eax, 0x80000000
          mov cr0, eax" :::"memory": "intel", "volatile");
    boot_write(b"3.6")
}

/// Test whether or not this system supports Multiboot 2
#[cold]
#[inline(always)]
unsafe fn is_multiboot_supported() -> bool {
    const MULTIBOOT_MAGIC: usize = 0x36d76289;
    let eax: usize;
    asm!("mov eax, $0" : "=r"(eax) ::: "intel");
    eax == MULTIBOOT_MAGIC
}

#[cold]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _start() {
    boot_write(b"0");
    asm!("cli");

    // 1. Move Multiboot info pointer to edi
    asm!("mov edi, ebx" :::: "intel");
    boot_write(b"1");

    // 2. make sure the system supports SOS
    // TODO: port this from boot.asm
    if !is_multiboot_supported() {
        loop { boot_write(b"ERROR: multiboot not supported!"); }
    }
    boot_write(b"2");

    // 3. if everything is okay, create the page tables and start long mode
    create_page_tables();
    set_long_mode();

    // 4. load the 64-bit GDT
    GdtPointer::from(&GDT).load();
    boot_write(b"4");

    // 6. jump to the 64-bit boot subroutine.
    asm!("ljmpl $$8, $$long_mode_init");

}
<|endoftext|>


<commit_before>use crate::{channels::Channels, Result};
use parking_lot::Mutex;
use std::{
    sync::Arc,
    time::{Duration, Instant},
};

#[derive(Clone)]
pub struct Heartbeat {
    channels: Channels,
    inner: Arc<Mutex<Inner>>,
}

impl Heartbeat {
    pub(crate) fn new(channels: Channels) -> Self {
        let inner = Default::default();
        Self { channels, inner }
    }

    pub(crate) fn set_timeout(&self, timeout: Duration) {
        self.inner.lock().timeout = Some(timeout);
    }

    pub fn get_heartbeat(&self) -> Option<Duration> {
        self.inner.lock().timeout
    }

    pub fn poll_timeout(&self) -> Result<Option<Duration>> {
        self.inner.lock().poll_timeout(&self.channels)
    }

    pub fn send(&self) -> Result<()> {
        self.channels.send_heartbeat()
    }

    pub(crate) fn update_last_write(&self) {
        self.inner.lock().update_last_write();
    }
}

struct Inner {
    last_write: Instant,
    timeout: Option<Duration>,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            last_write: Instant::now(),
            timeout: None,
        }
    }
}

impl Inner {
    fn poll_timeout(&mut self, channels: &Channels) -> Result<Option<Duration>> {
        self.timeout
            .map(|timeout| {
                timeout
                    .checked_sub(self.last_write.elapsed())
                    .map(Ok)
                    .unwrap_or_else(|| {
                        // Update last_write so that if we cannot write to the socket yet, we don't enqueue countless heartbeats
                        self.update_last_write();
                        channels.send_heartbeat()?;
                        Ok(timeout)
                    })
            })
            .transpose()
    }

    fn update_last_write(&mut self) {
        self.last_write = Instant::now();
    }
}
<commit_msg>impl Debug for Heartbeat<commit_after>use crate::{channels::Channels, Result};
use parking_lot::Mutex;
use std::{
    fmt,
    sync::Arc,
    time::{Duration, Instant},
};

#[derive(Clone)]
pub struct Heartbeat {
    channels: Channels,
    inner: Arc<Mutex<Inner>>,
}

impl Heartbeat {
    pub(crate) fn new(channels: Channels) -> Self {
        let inner = Default::default();
        Self { channels, inner }
    }

    pub(crate) fn set_timeout(&self, timeout: Duration) {
        self.inner.lock().timeout = Some(timeout);
    }

    pub fn get_heartbeat(&self) -> Option<Duration> {
        self.inner.lock().timeout
    }

    pub fn poll_timeout(&self) -> Result<Option<Duration>> {
        self.inner.lock().poll_timeout(&self.channels)
    }

    pub fn send(&self) -> Result<()> {
        self.channels.send_heartbeat()
    }

    pub(crate) fn update_last_write(&self) {
        self.inner.lock().update_last_write();
    }
}

impl fmt::Debug for Heartbeat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Heartbeat").finish()
    }
}

struct Inner {
    last_write: Instant,
    timeout: Option<Duration>,
}

impl Default for Inner {
    fn default() -> Self {
        Self {
            last_write: Instant::now(),
            timeout: None,
        }
    }
}

impl Inner {
    fn poll_timeout(&mut self, channels: &Channels) -> Result<Option<Duration>> {
        self.timeout
            .map(|timeout| {
                timeout
                    .checked_sub(self.last_write.elapsed())
                    .map(Ok)
                    .unwrap_or_else(|| {
                        // Update last_write so that if we cannot write to the socket yet, we don't enqueue countless heartbeats
                        self.update_last_write();
                        channels.send_heartbeat()?;
                        Ok(timeout)
                    })
            })
            .transpose()
    }

    fn update_last_write(&mut self) {
        self.last_write = Instant::now();
    }
}
<|endoftext|>


<commit_before>use bytes::Bytes;
use futures::{Poll, Stream};
use futures::sync::mpsc;
use tokio_proto;

use http::Chunk;

pub type TokioBody = tokio_proto::streaming::Body<Chunk, ::Error>;

/// A `Stream` for `Chunk`s used in requests and responses.
#[must_use = "streams do nothing unless polled"]
#[derive(Debug)]
pub struct Body(TokioBody);

impl Body {
    /// Return an empty body stream
    #[inline]
    pub fn empty() -> Body {
        Body(TokioBody::empty())
    }

    /// Return a body stream with an associated sender half
    #[inline]
    pub fn pair() -> (mpsc::Sender<Result<Chunk, ::Error>>, Body) {
        let (tx, rx) = TokioBody::pair();
        let rx = Body(rx);
        (tx, rx)
    }
}

impl Default for Body {
    #[inline]
    fn default() -> Body {
        Body::empty()
    }
}

impl Stream for Body {
    type Item = Chunk;
    type Error = ::Error;

    #[inline]
    fn poll(&mut self) -> Poll<Option<Chunk>, ::Error> {
        self.0.poll()
    }
}

impl From<Body> for tokio_proto::streaming::Body<Chunk, ::Error> {
    #[inline]
    fn from(b: Body) -> tokio_proto::streaming::Body<Chunk, ::Error> {
        b.0
    }
}

impl From<tokio_proto::streaming::Body<Chunk, ::Error>> for Body {
    #[inline]
    fn from(tokio_body: tokio_proto::streaming::Body<Chunk, ::Error>) -> Body {
        Body(tokio_body)
    }
}

impl From<mpsc::Receiver<Result<Chunk, ::Error>>> for Body {
    #[inline]
    fn from(src: mpsc::Receiver<Result<Chunk, ::Error>>) -> Body {
        Body(src.into())
    }
}

impl From<Chunk> for Body {
    #[inline]
    fn from (chunk: Chunk) -> Body {
        Body(TokioBody::from(chunk))
    }
}

impl From<Bytes> for Body {
    #[inline]
    fn from (bytes: Bytes) -> Body {
        Body(TokioBody::from(Chunk::from(bytes)))
    }
}

impl From<Vec<u8>> for Body {
    #[inline]
    fn from (vec: Vec<u8>) -> Body {
        Body(TokioBody::from(Chunk::from(vec)))
    }
}

impl From<&'static [u8]> for Body {
    #[inline]
    fn from (slice: &'static [u8]) -> Body {
        Body(TokioBody::from(Chunk::from(slice)))
    }
}

impl From<String> for Body {
    #[inline]
    fn from (s: String) -> Body {
        Body(TokioBody::from(Chunk::from(s.into_bytes())))
    }
}

impl From<&'static str> for Body {
    #[inline]
    fn from (slice: &'static str) -> Body {
        Body(TokioBody::from(Chunk::from(slice.as_bytes())))
    }
}

impl From<Option<Body>> for Body {
    #[inline]
    fn from (body: Option<Body>) -> Body {
        body.unwrap_or_default()
    }
}

fn _assert_send_sync() {
    fn _assert_send<T: Send>() {}
    fn _assert_sync<T: Sync>() {}

    _assert_send::<Body>();
    _assert_send::<Chunk>();
    _assert_sync::<Chunk>();
}

#[test]
fn test_body_stream_concat() {
    use futures::{Sink, Stream, Future};
    let (tx, body) = Body::pair();

    ::std::thread::spawn(move || {
        let tx = tx.send(Ok("hello ".into())).wait().unwrap();
        tx.send(Ok("world".into())).wait().unwrap();
    });

    let total = body.concat2().wait().unwrap();
    assert_eq!(total.as_ref(), b"hello world");

}
<commit_msg>feat(http): add Body::from(cow) for bytes and strings This change adds the ability to use Cow<'static, [u8]> and Cow<'static, str> for the body of a HTTP request or response. This makes it easier to create abstractions that serve static web pages, redirect messages and the like.<commit_after>use bytes::Bytes;
use futures::{Poll, Stream};
use futures::sync::mpsc;
use tokio_proto;
use std::borrow::Cow;

use http::Chunk;

pub type TokioBody = tokio_proto::streaming::Body<Chunk, ::Error>;

/// A `Stream` for `Chunk`s used in requests and responses.
#[must_use = "streams do nothing unless polled"]
#[derive(Debug)]
pub struct Body(TokioBody);

impl Body {
    /// Return an empty body stream
    #[inline]
    pub fn empty() -> Body {
        Body(TokioBody::empty())
    }

    /// Return a body stream with an associated sender half
    #[inline]
    pub fn pair() -> (mpsc::Sender<Result<Chunk, ::Error>>, Body) {
        let (tx, rx) = TokioBody::pair();
        let rx = Body(rx);
        (tx, rx)
    }
}

impl Default for Body {
    #[inline]
    fn default() -> Body {
        Body::empty()
    }
}

impl Stream for Body {
    type Item = Chunk;
    type Error = ::Error;

    #[inline]
    fn poll(&mut self) -> Poll<Option<Chunk>, ::Error> {
        self.0.poll()
    }
}

impl From<Body> for tokio_proto::streaming::Body<Chunk, ::Error> {
    #[inline]
    fn from(b: Body) -> tokio_proto::streaming::Body<Chunk, ::Error> {
        b.0
    }
}

impl From<tokio_proto::streaming::Body<Chunk, ::Error>> for Body {
    #[inline]
    fn from(tokio_body: tokio_proto::streaming::Body<Chunk, ::Error>) -> Body {
        Body(tokio_body)
    }
}

impl From<mpsc::Receiver<Result<Chunk, ::Error>>> for Body {
    #[inline]
    fn from(src: mpsc::Receiver<Result<Chunk, ::Error>>) -> Body {
        Body(src.into())
    }
}

impl From<Chunk> for Body {
    #[inline]
    fn from (chunk: Chunk) -> Body {
        Body(TokioBody::from(chunk))
    }
}

impl From<Bytes> for Body {
    #[inline]
    fn from (bytes: Bytes) -> Body {
        Body(TokioBody::from(Chunk::from(bytes)))
    }
}

impl From<Vec<u8>> for Body {
    #[inline]
    fn from (vec: Vec<u8>) -> Body {
        Body(TokioBody::from(Chunk::from(vec)))
    }
}

impl From<&'static [u8]> for Body {
    #[inline]
    fn from (slice: &'static [u8]) -> Body {
        Body(TokioBody::from(Chunk::from(slice)))
    }
}

impl From<Cow<'static, [u8]>> for Body {
    #[inline]
    fn from (cow: Cow<'static, [u8]>) -> Body {
		if let Cow::Borrowed(value) = cow {
			Body::from(value)
		} else {
			Body::from(cow.to_owned())
		}
    }
}

impl From<String> for Body {
    #[inline]
    fn from (s: String) -> Body {
        Body(TokioBody::from(Chunk::from(s.into_bytes())))
    }
}

impl From<&'static str> for Body {
    #[inline]
    fn from (slice: &'static str) -> Body {
        Body(TokioBody::from(Chunk::from(slice.as_bytes())))
    }
}

impl From<Cow<'static, str>> for Body {
    #[inline]
    fn from (cow: Cow<'static, str>) -> Body {
		if let Cow::Borrowed(value) = cow {
			Body::from(value)
		} else {
			Body::from(cow.to_owned())
		}
    }
}

impl From<Option<Body>> for Body {
    #[inline]
    fn from (body: Option<Body>) -> Body {
        body.unwrap_or_default()
    }
}

fn _assert_send_sync() {
    fn _assert_send<T: Send>() {}
    fn _assert_sync<T: Sync>() {}

    _assert_send::<Body>();
    _assert_send::<Chunk>();
    _assert_sync::<Chunk>();
}

#[test]
fn test_body_stream_concat() {
    use futures::{Sink, Stream, Future};
    let (tx, body) = Body::pair();

    ::std::thread::spawn(move || {
        let tx = tx.send(Ok("hello ".into())).wait().unwrap();
        tx.send(Ok("world".into())).wait().unwrap();
    });

    let total = body.concat2().wait().unwrap();
    assert_eq!(total.as_ref(), b"hello world");

}
<|endoftext|>


<commit_before>//! Types and traits for working with the Matrix protocol.
//!
//! This crate re-exports things from all of the other ruma crates so you don't
//! have to manually keep all the versions in sync.
//!
//! Which crates are re-exported can be configured through cargo features.
//! Depending on which parts of Matrix are relevant to you, activate the
//! following features:
//!
//! * `client-api` for the client-server API
//! * `federation-api` for the server-server (federation) API
//! * `appservice-api` for the application service API

#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[doc(no_inline)]
pub use assign::assign;
#[doc(no_inline)]
pub use js_int::{int, uint, Int, UInt};

pub use ruma_common::*;
#[doc(inline)]
pub use ruma_identifiers as identifiers;
#[doc(inline)]
pub use ruma_serde as serde;

pub use ruma_serde::Outgoing;

#[allow(deprecated)] // Allow re-export of deprecated items
pub use ruma_identifiers::{
    device_id, device_key_id, event_id, room_alias_id, room_id, room_version_id, server_key_id,
    server_name, server_signing_key_id, user_id, DeviceId, DeviceKeyAlgorithm, DeviceKeyId,
    EventId, RoomAliasId, RoomId, RoomIdOrAliasId, RoomVersionId, ServerName, ServerSigningKeyId,
    SigningKeyAlgorithm, UserId,
};

#[cfg(feature = "events")]
#[cfg_attr(docsrs, doc(cfg(feature = "events")))]
#[doc(inline)]
pub use ruma_events as events;
#[cfg(feature = "signatures")]
#[cfg_attr(docsrs, doc(cfg(feature = "signatures")))]
#[doc(inline)]
pub use ruma_signatures as signatures;

/// Rust types for various Matrix APIs requests and responses and abstractions for them.
#[cfg(feature = "api")]
#[cfg_attr(docsrs, doc(cfg(feature = "api")))]
pub mod api {
    pub use ruma_api::*;

    #[cfg(feature = "appservice-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "appservice-api")))]
    #[doc(inline)]
    pub use ruma_appservice_api as appservice;
    #[cfg(feature = "client-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "client-api")))]
    #[doc(inline)]
    pub use ruma_client_api as client;
    #[cfg(feature = "federation-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "federation-api")))]
    #[doc(inline)]
    pub use ruma_federation_api as federation;
    #[cfg(feature = "identity-service-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "identity-service-api")))]
    #[doc(inline)]
    pub use ruma_identity_service_api as identity_service;
    #[cfg(feature = "push-gateway-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "push-gateway-api")))]
    #[doc(inline)]
    pub use ruma_push_gateway_api as push_gateway;
}
<commit_msg>Add more documentation about ruma crate features<commit_after>//! Types and traits for working with the Matrix protocol.
//!
//! This crate re-exports things from all of the other ruma crates so you don't
//! have to manually keep all the versions in sync.
//!
//! Which crates are re-exported can be configured through cargo features.
//! Depending on which parts of Matrix are relevant to you, activate the
//! following features:
//!
//! * `client-api` for the client-server API
//! * `federation-api` for the server-server (federation) API
//! * `appservice-api` for the application service API
//!
//! There's also the features `api`, `events` and `signatures` for the
//! submodules of the same names. Usually they are activated by one of the
//! other features when needed. If you are viewing this on `docs.rs`, you can
//! have a look at the feature dependencies by clicking 'Feature flags' in the
//! toolbar at the top.

#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]

#[doc(no_inline)]
pub use assign::assign;
#[doc(no_inline)]
pub use js_int::{int, uint, Int, UInt};

pub use ruma_common::*;
#[doc(inline)]
pub use ruma_identifiers as identifiers;
#[doc(inline)]
pub use ruma_serde as serde;

pub use ruma_serde::Outgoing;

#[allow(deprecated)] // Allow re-export of deprecated items
pub use ruma_identifiers::{
    device_id, device_key_id, event_id, room_alias_id, room_id, room_version_id, server_key_id,
    server_name, server_signing_key_id, user_id, DeviceId, DeviceKeyAlgorithm, DeviceKeyId,
    EventId, RoomAliasId, RoomId, RoomIdOrAliasId, RoomVersionId, ServerName, ServerSigningKeyId,
    SigningKeyAlgorithm, UserId,
};

#[cfg(feature = "events")]
#[cfg_attr(docsrs, doc(cfg(feature = "events")))]
#[doc(inline)]
pub use ruma_events as events;
#[cfg(feature = "signatures")]
#[cfg_attr(docsrs, doc(cfg(feature = "signatures")))]
#[doc(inline)]
pub use ruma_signatures as signatures;

/// Rust types for various Matrix APIs requests and responses and abstractions for them.
#[cfg(feature = "api")]
#[cfg_attr(docsrs, doc(cfg(feature = "api")))]
pub mod api {
    pub use ruma_api::*;

    #[cfg(feature = "appservice-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "appservice-api")))]
    #[doc(inline)]
    pub use ruma_appservice_api as appservice;
    #[cfg(feature = "client-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "client-api")))]
    #[doc(inline)]
    pub use ruma_client_api as client;
    #[cfg(feature = "federation-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "federation-api")))]
    #[doc(inline)]
    pub use ruma_federation_api as federation;
    #[cfg(feature = "identity-service-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "identity-service-api")))]
    #[doc(inline)]
    pub use ruma_identity_service_api as identity_service;
    #[cfg(feature = "push-gateway-api")]
    #[cfg_attr(docsrs, doc(cfg(feature = "push-gateway-api")))]
    #[doc(inline)]
    pub use ruma_push_gateway_api as push_gateway;
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate clap;
#[macro_use] extern crate semver;
extern crate toml;
extern crate url;
#[macro_use] extern crate version;

extern crate libimaglink;
extern crate libimagrt;
extern crate libimagstore;
extern crate libimagutil;

use std::process::exit;
use std::ops::Deref;
use std::error::Error;

use libimagrt::runtime::Runtime;
use libimagstore::error::StoreError;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagutil::trace::trace_error;
use libimaglink::external::ExternalLinker;
use clap::ArgMatches;
use url::Url;

mod ui;

use ui::build_ui;

fn main() {
    let name = "imag-link";
    let version = &version!()[..];
    let about = "Link entries";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.err().unwrap());
            exit(1);
        }
    };

    debug!("Hello. Logging was just enabled");
    debug!("I already set up the Runtime object and build the commandline interface parser.");
    debug!("Lets get rollin' ...");

    rt.cli()
        .subcommand_name()
        .map(|name| {
            match name {
                "internal" => handle_internal_linking(&rt),
                "external" => handle_external_linking(&rt),
                _ => {
                    warn!("No commandline call");
                    exit(1);
                },
            }
        });
}

fn handle_internal_linking(rt: &Runtime) {
    use libimaglink::internal::InternalLinker;
    use libimagutil::trace::trace_error;

    debug!("Handle internal linking call");
    let cmd = rt.cli().subcommand_matches("internal").unwrap();

    if cmd.is_present("list") {
        debug!("List...");
        for entry in cmd.value_of("list").unwrap().split(",") {
            debug!("Listing for '{}'", entry);
            match get_entry_by_name(rt, entry) {
                Ok(e) => {
                    e.get_internal_links()
                        .map(|links| {
                            let mut i = 0;
                            for link in links.iter().map(|l| l.to_str()).filter_map(|x| x) {
                                println!("{: <3}: {}", i, link);
                                i += 1;
                            }
                        });
                },

                Err(e) => {
                    trace_error(&e);
                    break;
                },
            }
        }
        debug!("Listing ready!");
    } else {
        let mut from = {
            let mut from = get_from_entry(&rt);
            if from.is_none() {
                warn!("No 'from' entry");
                exit(1);
            }
            from.unwrap()
        };
        debug!("Link from = {:?}", from.deref());

        let mut to = {
            let mut to = get_to_entries(&rt);
            if to.is_none() {
                warn!("No 'to' entry");
                exit(1);
            }
            to.unwrap()
        };
        debug!("Link to = {:?}", to.iter().map(|f| f.deref()).collect::<Vec<&Entry>>());

        match cmd.subcommand_name() {
            Some("add") => {
                for mut to_entry in to {
                    if let Err(e) = to_entry.add_internal_link(&mut from) {
                        trace_error(&e);
                        exit(1);
                    }
                }
            },

            Some("remove") => {
                for mut to_entry in to {
                    if let Err(e) = to_entry.remove_internal_link(&mut from) {
                        trace_error(&e);
                        exit(1);
                    }
                }
            },

            _ => unreachable!(),
        };
    }
}

fn get_from_entry<'a>(rt: &'a Runtime) -> Option<FileLockEntry<'a>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .value_of("from")
        .and_then(|from_name| {
            match get_entry_by_name(rt, from_name) {
                Err(e) => {
                    debug!("We couldn't get the entry from name: '{:?}'", from_name);
                    trace_error(&e); None
                },
                Ok(e) => Some(e),
            }

        })
}

fn get_to_entries<'a>(rt: &'a Runtime) -> Option<Vec<FileLockEntry<'a>>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .values_of("to")
        .map(|values| {
            let mut v = vec![];
            for entry in values.map(|v| get_entry_by_name(rt, v)) {
                match entry {
                    Err(e) => trace_error(&e),
                    Ok(e) => v.push(e),
                }
            }
            v
        })
}

fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<FileLockEntry<'a>, StoreError> {
    use libimagstore::storeid::build_entry_path;
    build_entry_path(rt.store(), name)
        .and_then(|path| rt.store().retrieve(path))
}

fn handle_external_linking(rt: &Runtime) {
    use libimagutil::trace::trace_error;

    let scmd       = rt.cli().subcommand_matches("external").unwrap();
    let entry_name = scmd.value_of("id").unwrap(); // enforced by clap
    let entry      = get_entry_by_name(rt, entry_name);
    if entry.is_err() {
        trace_error(&entry.err().unwrap());
        exit(1);
    }
    let mut entry = entry.unwrap();

    if scmd.is_present("add") {
        add_link_to_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("remove") {
        remove_link_from_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("set") {
        set_links_for_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("list") {
        list_links_for_entry(rt.store(), &mut entry);
        return;
    }

    panic!("Clap failed to enforce one of 'add', 'remove', 'set' or 'list'");
}

fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let link = matches.value_of("add").unwrap();

    let link = Url::parse(link);
    if link.is_err() {
        trace_error(&link.err().unwrap());
        exit(1);
    }
    let link = link.unwrap();

    if let Err(e) = entry.add_external_link(store, link) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let link = matches.value_of("remove").unwrap();

    let link = Url::parse(link);
    if link.is_err() {
        trace_error(&link.err().unwrap());
        exit(1);
    }
    let link = link.unwrap();

    if let Err(e) = entry.remove_external_link(store, link) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let links = matches
        .value_of("links")
        .map(String::from)
        .unwrap()
        .split(",")
        .map(|uri| {
            match Url::parse(uri) {
                Err(e) => {
                    warn!("Could not parse '{}' as URL, ignoring", uri);
                    trace_error(&e);
                    None
                },
                Ok(u) => Some(u),
            }
        })
        .filter_map(|x| x)
        .collect();

    if let Err(e) = entry.set_external_links(store, links) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) {
    let res = entry.get_external_links(store)
        .and_then(|links| {
            let mut i = 0;
            for link in links {
                println!("{: <3}: {}", i, link);
                i += 1;
            }
            Ok(())
        });

    match res {
        Err(e) => {
            trace_error(&e);
        },
        Ok(_) => {
            info!("Ok");
        },
    }
}

<commit_msg>Add debugging output in handle_external_linking()<commit_after>#[macro_use] extern crate log;
extern crate clap;
#[macro_use] extern crate semver;
extern crate toml;
extern crate url;
#[macro_use] extern crate version;

extern crate libimaglink;
extern crate libimagrt;
extern crate libimagstore;
extern crate libimagutil;

use std::process::exit;
use std::ops::Deref;
use std::error::Error;

use libimagrt::runtime::Runtime;
use libimagstore::error::StoreError;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagutil::trace::trace_error;
use libimaglink::external::ExternalLinker;
use clap::ArgMatches;
use url::Url;

mod ui;

use ui::build_ui;

fn main() {
    let name = "imag-link";
    let version = &version!()[..];
    let about = "Link entries";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));
    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.err().unwrap());
            exit(1);
        }
    };

    debug!("Hello. Logging was just enabled");
    debug!("I already set up the Runtime object and build the commandline interface parser.");
    debug!("Lets get rollin' ...");

    rt.cli()
        .subcommand_name()
        .map(|name| {
            match name {
                "internal" => handle_internal_linking(&rt),
                "external" => handle_external_linking(&rt),
                _ => {
                    warn!("No commandline call");
                    exit(1);
                },
            }
        });
}

fn handle_internal_linking(rt: &Runtime) {
    use libimaglink::internal::InternalLinker;
    use libimagutil::trace::trace_error;

    debug!("Handle internal linking call");
    let cmd = rt.cli().subcommand_matches("internal").unwrap();

    if cmd.is_present("list") {
        debug!("List...");
        for entry in cmd.value_of("list").unwrap().split(",") {
            debug!("Listing for '{}'", entry);
            match get_entry_by_name(rt, entry) {
                Ok(e) => {
                    e.get_internal_links()
                        .map(|links| {
                            let mut i = 0;
                            for link in links.iter().map(|l| l.to_str()).filter_map(|x| x) {
                                println!("{: <3}: {}", i, link);
                                i += 1;
                            }
                        });
                },

                Err(e) => {
                    trace_error(&e);
                    break;
                },
            }
        }
        debug!("Listing ready!");
    } else {
        let mut from = {
            let mut from = get_from_entry(&rt);
            if from.is_none() {
                warn!("No 'from' entry");
                exit(1);
            }
            from.unwrap()
        };
        debug!("Link from = {:?}", from.deref());

        let mut to = {
            let mut to = get_to_entries(&rt);
            if to.is_none() {
                warn!("No 'to' entry");
                exit(1);
            }
            to.unwrap()
        };
        debug!("Link to = {:?}", to.iter().map(|f| f.deref()).collect::<Vec<&Entry>>());

        match cmd.subcommand_name() {
            Some("add") => {
                for mut to_entry in to {
                    if let Err(e) = to_entry.add_internal_link(&mut from) {
                        trace_error(&e);
                        exit(1);
                    }
                }
            },

            Some("remove") => {
                for mut to_entry in to {
                    if let Err(e) = to_entry.remove_internal_link(&mut from) {
                        trace_error(&e);
                        exit(1);
                    }
                }
            },

            _ => unreachable!(),
        };
    }
}

fn get_from_entry<'a>(rt: &'a Runtime) -> Option<FileLockEntry<'a>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .value_of("from")
        .and_then(|from_name| {
            match get_entry_by_name(rt, from_name) {
                Err(e) => {
                    debug!("We couldn't get the entry from name: '{:?}'", from_name);
                    trace_error(&e); None
                },
                Ok(e) => Some(e),
            }

        })
}

fn get_to_entries<'a>(rt: &'a Runtime) -> Option<Vec<FileLockEntry<'a>>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .values_of("to")
        .map(|values| {
            let mut v = vec![];
            for entry in values.map(|v| get_entry_by_name(rt, v)) {
                match entry {
                    Err(e) => trace_error(&e),
                    Ok(e) => v.push(e),
                }
            }
            v
        })
}

fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<FileLockEntry<'a>, StoreError> {
    use libimagstore::storeid::build_entry_path;
    build_entry_path(rt.store(), name)
        .and_then(|path| rt.store().retrieve(path))
}

fn handle_external_linking(rt: &Runtime) {
    use libimagutil::trace::trace_error;

    let scmd       = rt.cli().subcommand_matches("external").unwrap();
    let entry_name = scmd.value_of("id").unwrap(); // enforced by clap
    let entry      = get_entry_by_name(rt, entry_name);
    if entry.is_err() {
        trace_error(&entry.err().unwrap());
        exit(1);
    }
    let mut entry = entry.unwrap();

    if scmd.is_present("add") {
        debug!("Adding link to entry!");
        add_link_to_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("remove") {
        debug!("Removing link from entry!");
        remove_link_from_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("set") {
        debug!("Setting links in entry!");
        set_links_for_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("list") {
        debug!("Listing links in entry!");
        list_links_for_entry(rt.store(), &mut entry);
        return;
    }

    panic!("Clap failed to enforce one of 'add', 'remove', 'set' or 'list'");
}

fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let link = matches.value_of("add").unwrap();

    let link = Url::parse(link);
    if link.is_err() {
        debug!("URL parsing error...");
        trace_error(&link.err().unwrap());
        debug!("Exiting");
        exit(1);
    }
    let link = link.unwrap();

    if let Err(e) = entry.add_external_link(store, link) {
        debug!("Error while adding external link...");
        trace_error(&e);
    } else {
        debug!("Everything worked well");
        info!("Ok");
    }
}

fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let link = matches.value_of("remove").unwrap();

    let link = Url::parse(link);
    if link.is_err() {
        trace_error(&link.err().unwrap());
        exit(1);
    }
    let link = link.unwrap();

    if let Err(e) = entry.remove_external_link(store, link) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let links = matches
        .value_of("links")
        .map(String::from)
        .unwrap()
        .split(",")
        .map(|uri| {
            match Url::parse(uri) {
                Err(e) => {
                    warn!("Could not parse '{}' as URL, ignoring", uri);
                    trace_error(&e);
                    None
                },
                Ok(u) => Some(u),
            }
        })
        .filter_map(|x| x)
        .collect();

    if let Err(e) = entry.set_external_links(store, links) {
        trace_error(&e);
    } else {
        info!("Ok");
    }
}

fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) {
    let res = entry.get_external_links(store)
        .and_then(|links| {
            let mut i = 0;
            for link in links {
                println!("{: <3}: {}", i, link);
                i += 1;
            }
            Ok(())
        });

    match res {
        Err(e) => {
            trace_error(&e);
        },
        Ok(_) => {
            info!("Ok");
        },
    }
}

<|endoftext|>


<commit_before>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagentryview;
#[macro_use] extern crate libimagerror;

use std::process::exit;
use std::path::PathBuf;

use libimagrt::setup::generate_runtime_setup;
use libimagerror::trace::trace_error;
use libimagentryview::builtin::stdout::StdoutViewer;
use libimagentryview::builtin::versions::VersionsViewer;
use libimagentryview::viewer::Viewer;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup( "imag-view",
                                     &version!()[..],
                                     "View entries (readonly)",
                                     build_ui);

    let entry_id     = rt.cli().value_of("id").unwrap(); // enforced by clap
    let view_header  = rt.cli().is_present("view-header");
    let view_content = rt.cli().is_present("view-content");

    let scmd = match rt.cli().subcommand_matches("view-in") {
        None => {
            debug!("No commandline call");
            exit(1); // we can afford not-executing destructors here
        }
        Some(s) => s,
    };

    let entry = match rt.store().get(PathBuf::from(entry_id)) {
        Ok(Some(fle)) => fle,
        Ok(None) => {
            error!("Cannot get {}, there is no such id in the store", entry_id);
            exit(1);
        }
        Err(e) => {
            trace_error(&e);
            exit(1); // we can afford not-executing destructors here
        }
    };

    let res = if rt.cli().is_present("versions") {
        VersionsViewer::new(rt.store()).view_entry(&entry)
    } else {
        if scmd.is_present("view-in-stdout") {
        } else if scmd.is_present("view-in-ui") {
            warn!("Viewing in UI is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-browser") {
            warn!("Viewing in browser is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-texteditor") {
            warn!("Viewing in texteditor is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-custom") {
            warn!("Viewing in custom is currently not supported, switch to stdout");
        }

        StdoutViewer::new(view_header, view_content).view_entry(&entry)
    };

    if let Err(e) = res {
        trace_error(&e);
        exit(1);
    }
}

<commit_msg>shorten exit on error<commit_after>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagentryview;
#[macro_use] extern crate libimagerror;

use std::process::exit;
use std::path::PathBuf;

use libimagrt::setup::generate_runtime_setup;
use libimagerror::trace::trace_error_exit;
use libimagentryview::builtin::stdout::StdoutViewer;
use libimagentryview::builtin::versions::VersionsViewer;
use libimagentryview::viewer::Viewer;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup( "imag-view",
                                     &version!()[..],
                                     "View entries (readonly)",
                                     build_ui);

    let entry_id     = rt.cli().value_of("id").unwrap(); // enforced by clap
    let view_header  = rt.cli().is_present("view-header");
    let view_content = rt.cli().is_present("view-content");

    let scmd = match rt.cli().subcommand_matches("view-in") {
        None => {
            debug!("No commandline call");
            exit(1); // we can afford not-executing destructors here
        }
        Some(s) => s,
    };

    let entry = match rt.store().get(PathBuf::from(entry_id)) {
        Ok(Some(fle)) => fle,
        Ok(None) => {
            error!("Cannot get {}, there is no such id in the store", entry_id);
            exit(1);
        }
        Err(e) => {
            trace_error_exit(&e, 1);
        }
    };

    let res = if rt.cli().is_present("versions") {
        VersionsViewer::new(rt.store()).view_entry(&entry)
    } else {
        if scmd.is_present("view-in-stdout") {
        } else if scmd.is_present("view-in-ui") {
            warn!("Viewing in UI is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-browser") {
            warn!("Viewing in browser is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-texteditor") {
            warn!("Viewing in texteditor is currently not supported, switch to stdout");
        } else if scmd.is_present("view-in-custom") {
            warn!("Viewing in custom is currently not supported, switch to stdout");
        }

        StdoutViewer::new(view_header, view_content).view_entry(&entry)
    };

    if let Err(e) = res {
        trace_error_exit(&e, 1);
    }
}

<|endoftext|>