<commit_before>//! GPU handle and types.

use crate::{
    raster::{raster_path, Method},
    uniforms::*,
    Result,
};
use glium::{
    backend::{
        glutin::{headless::Headless, Display},
        Context,
        Facade,
    },
    glutin::EventsLoop,
    implement_vertex,
    index::PrimitiveType,
    texture::{
        texture2d::Texture2d,
        texture2d_multisample::Texture2dMultisample,
        MipmapsOption,
        RawImage2d,
        UncompressedFloatFormat,
    },
    uniforms::{MagnifySamplerFilter, UniformValue, Uniforms},
    Blend,
    BlendingFunction,
    DrawParameters,
    Frame,
    IndexBuffer,
    LinearBlendingFactor,
    Program,
    Surface,
    VertexBuffer,
};
use glutin::dpi::PhysicalSize;
use itertools::Itertools;
use lyon_path::Builder;
use palette::LinSrgba;
use rand::random;
use std::rc::Rc;

#[derive(Debug, Copy, Clone)]
pub struct GpuVertex {
    pub vpos: [f32; 2],
    pub vcol: [f32; 4],
}

implement_vertex!(GpuVertex, vpos, vcol);

pub(crate) const TEXTURE_FORMAT: UncompressedFloatFormat = UncompressedFloatFormat::F32F32F32F32;

pub const VERTEX_SHADER: &str = include_str!("shaders/default.vert");
const FRAGMENT_SHADER: &str = include_str!("shaders/default.frag");

struct NoUniforms;

impl Uniforms for NoUniforms {
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, _f: F) {}
}

#[derive(Default, Clone)]
pub struct UniformBuffer {
    user_uniforms: Option<Rc<dyn OwnedUniforms>>,
    uniforms: Vec<(String, UniformValue<'static>)>,
}

impl UniformBuffer {
    pub fn push(&mut self, name: String, value: UniformValue<'static>) {
        self.uniforms.push((name, value));
    }
}

impl Uniforms for UniformBuffer {
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, mut f: F) {
        if let Some(user_uniforms) = self.user_uniforms.as_ref().map(Rc::as_ref) {
            user_uniforms.visit_owned_values(&mut |name, v| {
                let uniform_value = v.into_uniform_value();
                let uniform_value: UniformValue<'a> = unsafe { std::mem::transmute(uniform_value) };
                f(name, uniform_value)
            });
        }
        for (name, value) in &self.uniforms {
            f(name.as_str(), *value);
        }
    }
}

impl<U> From<U> for UniformBuffer
where
    U: OwnedUniforms + 'static,
{
    fn from(src: U) -> Self {
        UniformBuffer {
            user_uniforms: Some(Rc::new(src)),
            uniforms: vec![],
        }
    }
}

/// A shader which can be used to shade paths. See `ShaderProgram` for construction.
#[derive(Clone)]
pub struct Shader {
    id: u64,
    program: Rc<Program>,
    uniforms: UniformBuffer,
}

/// A rasterable element in a composition.
pub struct Element {
    pub path: Builder,
    pub color: LinSrgba,
    pub raster_method: Method,
    pub shader: Shader,
}

pub struct DisplayFacade(Display);

impl Facade for DisplayFacade {
    fn get_context(&self) -> &Rc<Context> { self.0.get_context() }
}

pub trait FacadeExt: Facade {
    fn get_frame(&self) -> Option<Frame> { None }
}

impl FacadeExt for Headless {}

impl FacadeExt for DisplayFacade {
    fn get_frame(&self) -> Option<Frame> { Some(self.0.draw()) }
}

/// A handle to the GPU for managing buffers and shaders.
#[derive(Clone)]
pub struct Gpu {
    pub(crate) ctx: Rc<dyn FacadeExt>,
    program: Rc<Program>,
    height_sign: f32,
}

struct GpuCommand<'a, S> {
    pub vertices: VertexBuffer<GpuVertex>,
    pub indices: IndexBuffer<u32>,
    pub target: &'a mut S,
    pub program: &'a Program,
    pub uniforms: &'a UniformBuffer,
}

impl Gpu {
    pub(crate) fn new() -> Result<(Self, EventsLoop)> {
        let events_loop = EventsLoop::new();
        let ctx = glium::glutin::ContextBuilder::new()
            .with_multisampling(0)
            .build_headless(
                &events_loop,
                PhysicalSize {
                    width: 0.0,
                    height: 0.0,
                },
            )?;
        let ctx = Rc::new(Headless::new(ctx)?);

        let program = Rc::new(Program::from_source(
            ctx.as_ref(),
            VERTEX_SHADER,
            FRAGMENT_SHADER,
            None,
        )?);

        Ok((
            Gpu {
                program,
                ctx,
                height_sign: 1.,
            },
            events_loop,
        ))
    }

    pub(crate) fn with_window(width: u32, height: u32) -> Result<(Self, EventsLoop, (u32, u32))> {
        let events_loop = EventsLoop::new();
        let wb = glium::glutin::WindowBuilder::new()
            .with_dimensions(glutin::dpi::LogicalSize {
                width: width as f64,
                height: height as f64,
            })
            .with_resizable(false)
            .with_title("Hello world");
        let cb = glium::glutin::ContextBuilder::new()
            .with_srgb(false)
            .with_multisampling(8);
        let display = glium::Display::new(wb, cb, &events_loop).unwrap();
        let dimensions = display.get_framebuffer_dimensions();
        let ctx = Rc::new(DisplayFacade(display));

        let program = Rc::new(Program::from_source(
            ctx.as_ref(),
            VERTEX_SHADER,
            FRAGMENT_SHADER,
            None,
        )?);

        Ok((
            Gpu {
                program,
                ctx,
                height_sign: -1.,
            },
            events_loop,
            dimensions,
        ))
    }

    pub(crate) fn get_frame(&self) -> Option<Frame> { self.ctx.get_frame() }

    pub(crate) fn default_shader(&self) -> Shader {
        Shader {
            id: random(),
            program: self.program.clone(),
            uniforms: UniformBuffer::default(),
        }
    }

    pub(crate) fn compile_glsl(&self, source: &str) -> Result<Rc<Program>> {
        Ok(Rc::new(Program::from_source(
            self.ctx.as_ref(),
            VERTEX_SHADER,
            source,
            None,
        )?))
    }

    pub(crate) fn build_shader(
        &self,
        program: Rc<Program>,
        uniforms: impl Into<UniformBuffer>,
    ) -> Shader {
        Shader {
            id: random(),
            program,
            uniforms: uniforms.into(),
        }
    }

    pub fn build_texture(&self, width: u32, height: u32) -> Result<Texture2dMultisample> {
        Ok(Texture2dMultisample::empty_with_format(
            self.ctx.as_ref(),
            TEXTURE_FORMAT,
            MipmapsOption::NoMipmap,
            width,
            height,
            /*samples=*/ 16,
        )?)
    }

    fn build_ram_texture(&self, width: u32, height: u32) -> Result<Texture2d> {
        Ok(Texture2d::empty_with_format(
            self.ctx.as_ref(),
            TEXTURE_FORMAT,
            MipmapsOption::NoMipmap,
            width,
            height,
        )?)
    }

    pub fn read_to_ram(&self, texture: &Texture2dMultisample) -> Result<RawImage2d<u8>> {
        let (width, height) = texture.dimensions();
        let target = self.build_ram_texture(width, height)?;
        texture.as_surface().blit_color(
            &glium::Rect {
                bottom: 0,
                left: 0,
                width,
                height,
            },
            &target.as_surface(),
            &glium::BlitTarget {
                bottom: 0,
                left: 0,
                width: width as i32,
                height: height as i32,
            },
            MagnifySamplerFilter::Linear,
        );
        Ok(target.read())
    }

    pub fn render(
        &self,
        width: u32,
        height: u32,
        elements: impl IntoIterator<Item = Element>,
        target: &mut impl Surface,
    ) -> Result<()> {
        let elements = elements.into_iter();
        for (_id, batch) in &elements.group_by(|e| e.shader.id) {
            let mut batch = batch.peekable();
            let mut first = if let Some(first) = batch.peek() {
                first.shader.clone()
            } else {
                println!("This is possible??");
                continue;
            };

            // TODO: reconcile conflicts between user uniforms and the defaults
            first.uniforms.push(
                String::from("_valora_width"),
                UniformValue::Float(width as f32),
            );
            first.uniforms.push(
                String::from("_valora_height"),
                UniformValue::Float(height as f32),
            );
            first.uniforms.push(
                String::from("_valora_height_sign"),
                UniformValue::Float(self.height_sign),
            );

            let (_, cpu_vertices, cpu_indices) = batch
                .try_fold::<_, _, Result<(u32, Vec<GpuVertex>, Vec<u32>)>>(
                    (0, vec![], vec![]),
                    |(idx, mut vertices, mut indices), element| {
                        let (mut new_vertices, new_indices) =
                            raster_path(element.path, element.raster_method, element.color)?;
                        vertices.append(&mut new_vertices);
                        indices.extend(new_indices.into_iter().map(|i| i + idx));
                        Ok((vertices.len() as u32, vertices, indices))
                    },
                )?;

            let vertices = VertexBuffer::new(self.ctx.as_ref(), cpu_vertices.as_slice())?;
            let indices = IndexBuffer::new(
                self.ctx.as_ref(),
                PrimitiveType::TrianglesList,
                cpu_indices.as_slice(),
            )?;

            self.draw_to_texture(GpuCommand {
                indices,
                vertices,
                target,
                program: first.program.as_ref(),
                uniforms: &first.uniforms,
            })?;
        }

        Ok(())
    }

    fn draw_to_texture<S: Surface>(&self, cmd: GpuCommand<S>) -> Result<()> {
        Ok(cmd.target.draw(
            &cmd.vertices,
            &cmd.indices,
            cmd.program,
            cmd.uniforms,
            &DrawParameters {
                blend: Blend {
                    color: BlendingFunction::Addition {
                        source: LinearBlendingFactor::SourceAlpha,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    },
                    alpha: BlendingFunction::Addition {
                        source: LinearBlendingFactor::One,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    },
                    constant_value: (0.0, 0.0, 0.0, 0.0),
                },
                line_width: Some(1.0),
                multisampling: true,
                dithering: false,
                smooth: Some(glium::draw_parameters::Smooth::Nicest),
                ..Default::default()
            },
        )?)
    }
}
<commit_msg>Name valora preview window<commit_after>//! GPU handle and types.

use crate::{
    raster::{raster_path, Method},
    uniforms::*,
    Result,
};
use glium::{
    backend::{
        glutin::{headless::Headless, Display},
        Context,
        Facade,
    },
    glutin::EventsLoop,
    implement_vertex,
    index::PrimitiveType,
    texture::{
        texture2d::Texture2d,
        texture2d_multisample::Texture2dMultisample,
        MipmapsOption,
        RawImage2d,
        UncompressedFloatFormat,
    },
    uniforms::{MagnifySamplerFilter, UniformValue, Uniforms},
    Blend,
    BlendingFunction,
    DrawParameters,
    Frame,
    IndexBuffer,
    LinearBlendingFactor,
    Program,
    Surface,
    VertexBuffer,
};
use glutin::dpi::PhysicalSize;
use itertools::Itertools;
use lyon_path::Builder;
use palette::LinSrgba;
use rand::random;
use std::rc::Rc;

#[derive(Debug, Copy, Clone)]
pub struct GpuVertex {
    pub vpos: [f32; 2],
    pub vcol: [f32; 4],
}

implement_vertex!(GpuVertex, vpos, vcol);

pub(crate) const TEXTURE_FORMAT: UncompressedFloatFormat = UncompressedFloatFormat::F32F32F32F32;

pub const VERTEX_SHADER: &str = include_str!("shaders/default.vert");
const FRAGMENT_SHADER: &str = include_str!("shaders/default.frag");

struct NoUniforms;

impl Uniforms for NoUniforms {
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, _f: F) {}
}

#[derive(Default, Clone)]
pub struct UniformBuffer {
    user_uniforms: Option<Rc<dyn OwnedUniforms>>,
    uniforms: Vec<(String, UniformValue<'static>)>,
}

impl UniformBuffer {
    pub fn push(&mut self, name: String, value: UniformValue<'static>) {
        self.uniforms.push((name, value));
    }
}

impl Uniforms for UniformBuffer {
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, mut f: F) {
        if let Some(user_uniforms) = self.user_uniforms.as_ref().map(Rc::as_ref) {
            user_uniforms.visit_owned_values(&mut |name, v| {
                let uniform_value = v.into_uniform_value();
                let uniform_value: UniformValue<'a> = unsafe { std::mem::transmute(uniform_value) };
                f(name, uniform_value)
            });
        }
        for (name, value) in &self.uniforms {
            f(name.as_str(), *value);
        }
    }
}

impl<U> From<U> for UniformBuffer
where
    U: OwnedUniforms + 'static,
{
    fn from(src: U) -> Self {
        UniformBuffer {
            user_uniforms: Some(Rc::new(src)),
            uniforms: vec![],
        }
    }
}

/// A shader which can be used to shade paths. See `ShaderProgram` for construction.
#[derive(Clone)]
pub struct Shader {
    id: u64,
    program: Rc<Program>,
    uniforms: UniformBuffer,
}

/// A rasterable element in a composition.
pub struct Element {
    pub path: Builder,
    pub color: LinSrgba,
    pub raster_method: Method,
    pub shader: Shader,
}

pub struct DisplayFacade(Display);

impl Facade for DisplayFacade {
    fn get_context(&self) -> &Rc<Context> { self.0.get_context() }
}

pub trait FacadeExt: Facade {
    fn get_frame(&self) -> Option<Frame> { None }
}

impl FacadeExt for Headless {}

impl FacadeExt for DisplayFacade {
    fn get_frame(&self) -> Option<Frame> { Some(self.0.draw()) }
}

/// A handle to the GPU for managing buffers and shaders.
#[derive(Clone)]
pub struct Gpu {
    pub(crate) ctx: Rc<dyn FacadeExt>,
    program: Rc<Program>,
    height_sign: f32,
}

struct GpuCommand<'a, S> {
    pub vertices: VertexBuffer<GpuVertex>,
    pub indices: IndexBuffer<u32>,
    pub target: &'a mut S,
    pub program: &'a Program,
    pub uniforms: &'a UniformBuffer,
}

impl Gpu {
    pub(crate) fn new() -> Result<(Self, EventsLoop)> {
        let events_loop = EventsLoop::new();
        let ctx = glium::glutin::ContextBuilder::new()
            .with_multisampling(0)
            .build_headless(
                &events_loop,
                PhysicalSize {
                    width: 0.0,
                    height: 0.0,
                },
            )?;
        let ctx = Rc::new(Headless::new(ctx)?);

        let program = Rc::new(Program::from_source(
            ctx.as_ref(),
            VERTEX_SHADER,
            FRAGMENT_SHADER,
            None,
        )?);

        Ok((
            Gpu {
                program,
                ctx,
                height_sign: 1.,
            },
            events_loop,
        ))
    }

    pub(crate) fn with_window(width: u32, height: u32) -> Result<(Self, EventsLoop, (u32, u32))> {
        let events_loop = EventsLoop::new();
        let wb = glium::glutin::WindowBuilder::new()
            .with_dimensions(glutin::dpi::LogicalSize {
                width: width as f64,
                height: height as f64,
            })
            .with_resizable(false)
            .with_title("valora");
        let cb = glium::glutin::ContextBuilder::new()
            .with_srgb(false)
            .with_multisampling(8);
        let display = glium::Display::new(wb, cb, &events_loop).unwrap();
        let dimensions = display.get_framebuffer_dimensions();
        let ctx = Rc::new(DisplayFacade(display));

        let program = Rc::new(Program::from_source(
            ctx.as_ref(),
            VERTEX_SHADER,
            FRAGMENT_SHADER,
            None,
        )?);

        Ok((
            Gpu {
                program,
                ctx,
                height_sign: -1.,
            },
            events_loop,
            dimensions,
        ))
    }

    pub(crate) fn get_frame(&self) -> Option<Frame> { self.ctx.get_frame() }

    pub(crate) fn default_shader(&self) -> Shader {
        Shader {
            id: random(),
            program: self.program.clone(),
            uniforms: UniformBuffer::default(),
        }
    }

    pub(crate) fn compile_glsl(&self, source: &str) -> Result<Rc<Program>> {
        Ok(Rc::new(Program::from_source(
            self.ctx.as_ref(),
            VERTEX_SHADER,
            source,
            None,
        )?))
    }

    pub(crate) fn build_shader(
        &self,
        program: Rc<Program>,
        uniforms: impl Into<UniformBuffer>,
    ) -> Shader {
        Shader {
            id: random(),
            program,
            uniforms: uniforms.into(),
        }
    }

    pub fn build_texture(&self, width: u32, height: u32) -> Result<Texture2dMultisample> {
        Ok(Texture2dMultisample::empty_with_format(
            self.ctx.as_ref(),
            TEXTURE_FORMAT,
            MipmapsOption::NoMipmap,
            width,
            height,
            /*samples=*/ 16,
        )?)
    }

    fn build_ram_texture(&self, width: u32, height: u32) -> Result<Texture2d> {
        Ok(Texture2d::empty_with_format(
            self.ctx.as_ref(),
            TEXTURE_FORMAT,
            MipmapsOption::NoMipmap,
            width,
            height,
        )?)
    }

    pub fn read_to_ram(&self, texture: &Texture2dMultisample) -> Result<RawImage2d<u8>> {
        let (width, height) = texture.dimensions();
        let target = self.build_ram_texture(width, height)?;
        texture.as_surface().blit_color(
            &glium::Rect {
                bottom: 0,
                left: 0,
                width,
                height,
            },
            &target.as_surface(),
            &glium::BlitTarget {
                bottom: 0,
                left: 0,
                width: width as i32,
                height: height as i32,
            },
            MagnifySamplerFilter::Linear,
        );
        Ok(target.read())
    }

    pub fn render(
        &self,
        width: u32,
        height: u32,
        elements: impl IntoIterator<Item = Element>,
        target: &mut impl Surface,
    ) -> Result<()> {
        let elements = elements.into_iter();
        for (_id, batch) in &elements.group_by(|e| e.shader.id) {
            let mut batch = batch.peekable();
            let mut first = if let Some(first) = batch.peek() {
                first.shader.clone()
            } else {
                println!("This is possible??");
                continue;
            };

            // TODO: reconcile conflicts between user uniforms and the defaults
            first.uniforms.push(
                String::from("_valora_width"),
                UniformValue::Float(width as f32),
            );
            first.uniforms.push(
                String::from("_valora_height"),
                UniformValue::Float(height as f32),
            );
            first.uniforms.push(
                String::from("_valora_height_sign"),
                UniformValue::Float(self.height_sign),
            );

            let (_, cpu_vertices, cpu_indices) = batch
                .try_fold::<_, _, Result<(u32, Vec<GpuVertex>, Vec<u32>)>>(
                    (0, vec![], vec![]),
                    |(idx, mut vertices, mut indices), element| {
                        let (mut new_vertices, new_indices) =
                            raster_path(element.path, element.raster_method, element.color)?;
                        vertices.append(&mut new_vertices);
                        indices.extend(new_indices.into_iter().map(|i| i + idx));
                        Ok((vertices.len() as u32, vertices, indices))
                    },
                )?;

            let vertices = VertexBuffer::new(self.ctx.as_ref(), cpu_vertices.as_slice())?;
            let indices = IndexBuffer::new(
                self.ctx.as_ref(),
                PrimitiveType::TrianglesList,
                cpu_indices.as_slice(),
            )?;

            self.draw_to_texture(GpuCommand {
                indices,
                vertices,
                target,
                program: first.program.as_ref(),
                uniforms: &first.uniforms,
            })?;
        }

        Ok(())
    }

    fn draw_to_texture<S: Surface>(&self, cmd: GpuCommand<S>) -> Result<()> {
        Ok(cmd.target.draw(
            &cmd.vertices,
            &cmd.indices,
            cmd.program,
            cmd.uniforms,
            &DrawParameters {
                blend: Blend {
                    color: BlendingFunction::Addition {
                        source: LinearBlendingFactor::SourceAlpha,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    },
                    alpha: BlendingFunction::Addition {
                        source: LinearBlendingFactor::One,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    },
                    constant_value: (0.0, 0.0, 0.0, 0.0),
                },
                line_width: Some(1.0),
                multisampling: true,
                dithering: false,
                smooth: Some(glium::draw_parameters::Smooth::Nicest),
                ..Default::default()
            },
        )?)
    }
}
<|endoftext|>


<commit_before>#[doc(hidden)]
pub mod filter;
mod joins;

use expression::{Expression, SelectableExpression, NonAggregate};
use query_builder::*;
#[doc(hidden)]
pub use self::joins::{InnerJoinSource, LeftOuterJoinSource};
use types::{FromSqlRow, NativeSqlType};

pub use self::joins::JoinTo;

/// Trait indicating that a record can be queried from the database. This trait
/// can be derived automatically. See the [codegen
/// documentation](https://github.com/sgrif/yaqb/tree/master/yaqb_codegen#derivequeriable)
/// for more.
pub trait Queriable<ST: NativeSqlType> {
    type Row: FromSqlRow<ST>;

    fn build(row: Self::Row) -> Self;
}

#[doc(hidden)]
pub trait QuerySource: Sized {
    fn from_clause(&self, out: &mut QueryBuilder) -> BuildQueryResult;
}

/// A column on a database table. Types which implement this trait should have
/// been generated by the [`table!`
/// macro](http://sgrif.github.io/yaqb/yaqb/macro.table!.html).
pub trait Column: Expression {
    type Table: Table;

    fn name() -> &'static str;
}

/// A SQL database table. Types which implement this trait should have
/// been generated by the [`table!`
/// macro](http://sgrif.github.io/yaqb/yaqb/macro.table!.html).
pub trait Table: QuerySource + AsQuery + Sized {
    type PrimaryKey: Column<Table=Self> + Expression + NonAggregate;
    type AllColumns: SelectableExpression<Self>;

    fn name() -> &'static str;
    fn primary_key(&self) -> Self::PrimaryKey;
    fn all_columns() -> Self::AllColumns;

    fn inner_join<T>(self, other: T) -> InnerJoinSource<Self, T> where
        T: Table,
        Self: JoinTo<T>,
    {
        InnerJoinSource::new(self, other)
    }

    fn left_outer_join<T>(self, other: T) -> LeftOuterJoinSource<Self, T> where
        T: Table,
        Self: JoinTo<T>,
    {
        LeftOuterJoinSource::new(self, other)
    }
}

impl<T: Table> UpdateTarget for T {
    type Table = Self;

    fn where_clause(&self, _out: &mut QueryBuilder) -> BuildQueryResult {
        Ok(())
    }

    fn table(&self) -> &Self::Table {
        self
    }
}
<commit_msg>Add module level documentation for the `query_source` module<commit_after>//! Types in this module are mostly internal and automatically generated. You
//! shouldn't need to interact with these types during normal usage, other than
//! the methods on [`Table`](trait.Table.html)
#[doc(hidden)]
pub mod filter;
mod joins;

use expression::{Expression, SelectableExpression, NonAggregate};
use query_builder::*;
#[doc(hidden)]
pub use self::joins::{InnerJoinSource, LeftOuterJoinSource};
use types::{FromSqlRow, NativeSqlType};

pub use self::joins::JoinTo;

/// Trait indicating that a record can be queried from the database. This trait
/// can be derived automatically. See the [codegen
/// documentation](https://github.com/sgrif/yaqb/tree/master/yaqb_codegen#derivequeriable)
/// for more.
pub trait Queriable<ST: NativeSqlType> {
    type Row: FromSqlRow<ST>;

    fn build(row: Self::Row) -> Self;
}

#[doc(hidden)]
pub trait QuerySource: Sized {
    fn from_clause(&self, out: &mut QueryBuilder) -> BuildQueryResult;
}

/// A column on a database table. Types which implement this trait should have
/// been generated by the [`table!` macro](../macro.table!.html).
pub trait Column: Expression {
    type Table: Table;

    fn name() -> &'static str;
}

/// A SQL database table. Types which implement this trait should have been
/// generated by the [`table!` macro](../macro.table!.html).
pub trait Table: QuerySource + AsQuery + Sized {
    type PrimaryKey: Column<Table=Self> + Expression + NonAggregate;
    type AllColumns: SelectableExpression<Self>;

    fn name() -> &'static str;
    fn primary_key(&self) -> Self::PrimaryKey;
    fn all_columns() -> Self::AllColumns;

    fn inner_join<T>(self, other: T) -> InnerJoinSource<Self, T> where
        T: Table,
        Self: JoinTo<T>,
    {
        InnerJoinSource::new(self, other)
    }

    fn left_outer_join<T>(self, other: T) -> LeftOuterJoinSource<Self, T> where
        T: Table,
        Self: JoinTo<T>,
    {
        LeftOuterJoinSource::new(self, other)
    }
}

impl<T: Table> UpdateTarget for T {
    type Table = Self;

    fn where_clause(&self, _out: &mut QueryBuilder) -> BuildQueryResult {
        Ok(())
    }

    fn table(&self) -> &Self::Table {
        self
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Debug, Display, Formatter};
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt;
use std::ops::Deref;
use std::process::exit;

use clap::ArgMatches;
use regex::Regex;

use runtime::Runtime;
use module::Module;

use storage::Store;
use storage::file::hash::FileHash;
use storage::file::id::FileID;
use storage::file::File;
use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
use module::helpers::cli::get_file_filter_by_cli;
use module::helpers::cli::CliFileFilter;

mod header;

use self::header::get_url_from_header;
use self::header::get_tags_from_header;

pub struct BM<'a> {
    rt: &'a Runtime<'a>,
}

impl<'a> BM<'a> {

    pub fn new(rt: &'a Runtime<'a>) -> BM<'a> {
        BM {
            rt: rt,
        }
    }

    fn runtime(&self) -> &Runtime {
        &self.rt
    }

    /**
     * Subcommand: add
     */
    fn command_add(&self, matches: &ArgMatches) -> bool {
        use std::process::exit;
        use self::header::build_header;

        let parser = Parser::new(JsonHeaderParser::new(None));

        let url    = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present

        if !self.validate_url(&url, &parser) {
            error!("URL validation failed, exiting.");
            exit(1);
        } else {
            debug!("Verification succeeded");
        }

        let tags   = matches.value_of("tags").and_then(|s| {
            Some(s.split(",").map(String::from).collect())
        }).unwrap_or(vec![]);

        debug!("Building header with");
        debug!("    url  = '{:?}'", url);
        debug!("    tags = '{:?}'", tags);
        let header = build_header(url, tags);

        let fileid = self.rt.store().new_file_with_header(self, header);
        self.rt.store().load(&fileid).and_then(|file| {
            info!("Created file in memory: {}", fileid);
            Some(self.rt.store().persist(&parser, file))
        }).unwrap_or(false)
    }

    fn validate_url<HP>(&self, url: &String, parser: &Parser<HP>) -> bool
        where HP: FileHeaderParser
    {
        use util::is_url;

        if !is_url(url) {
            error!("Url '{}' is not a valid URL. Will not store.", url);
            return false;
        }

        let is_in_store = self.rt
            .store()
            .load_for_module(self, parser)
            .iter()
            .any(|file| {
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url_in_store| {
                    &url_in_store == url
                }).unwrap_or(false)
            });

        if is_in_store {
            error!("URL '{}' seems to be in the store already", url);
            return false;
        }

        return true;
    }

    /**
     * Subcommand: list
     */
    fn command_list(&self, matches: &ArgMatches) -> bool {
        use ui::file::{FilePrinter, TablePrinter};
        use std::ops::Deref;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let files  = self.rt.store().load_for_module(self, &parser);
        let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());

        printer.print_files_custom(files.into_iter(),
            &|file| {
                let fl = file.deref().borrow();
                let hdr = fl.header();
                let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
                let tags = get_tags_from_header(hdr);

                debug!("Custom printer field: url  = '{:?}'", url);
                debug!("Custom printer field: tags = '{:?}'", tags);

                vec![url, tags.join(", ")]
            }
        );
        true
    }

    /**
     * Subcommand: remove
     */
    fn command_remove(&self, matches: &ArgMatches) -> bool {
        use std::process::exit;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser, matches, "id", "match", "tags", None);
        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can remove now: {:?}", file);
                let f = file.deref().borrow();
                self.rt.store().remove(f.id().clone())
            })
            .all(|x| x);

        if result {
            info!("Removing succeeded");
        } else {
            info!("Removing failed");
        }

        return result;
    }

    /**
     * Subcommand: add_tags
     */
    fn command_add_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            let mut new_tags = old_tags.clone();
            new_tags.append(&mut cli_tags.clone());
            new_tags
        })
    }

    /**
     * Subcommand: rm_tags
     */
    fn command_rm_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            old_tags.clone()
                .into_iter()
                .filter(|tag| !cli_tags.contains(tag))
                .collect()
        })
    }

    /**
     * Subcommand: set_tags
     */
    fn command_set_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            cli_tags.clone()
        })
    }

    /**
     * Helper function to alter the tags in a file
     */
    fn alter_tags_in_files<F>(&self, matches: &ArgMatches, generate_new_tags: F) -> bool
        where F: Fn(Vec<String>, &Vec<String>) -> Vec<String>
    {
        use self::header::rebuild_header_with_tags;

        let cli_tags = matches.value_of("tags")
                          .map(|ts| {
                            ts.split(",")
                              .map(String::from)
                              .collect::<Vec<String>>()
                          })
                          .unwrap_or(vec![]);

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser,
                                                                 matches,
                                                                 "with_id",
                                                                 "with_match",
                                                                 "with_tags",
                                                                 None);
        self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("Remove tags from file: {:?}", file);

                let hdr = {
                    let f = file.deref().borrow();
                    f.header().clone()
                };

                debug!("Tags:...");
                let old_tags = get_tags_from_header(&hdr);
                debug!("    old_tags = {:?}", &old_tags);
                debug!("    cli_tags = {:?}", &cli_tags);

                let new_tags = generate_new_tags(old_tags, &cli_tags);
                debug!("    new_tags = {:?}", &new_tags);

                let new_header = rebuild_header_with_tags(&hdr, new_tags)
                    .unwrap_or_else(|| {
                        error!("Could not rebuild header for file");
                        exit(1);
                    });
                {
                    let mut f_mut = file.deref().borrow_mut();
                    f_mut.set_header(new_header);
                }

                self.rt.store().persist(&parser, file);
                true
            })
            .all(|x| x)
    }

}

/**
 * Trait implementation for BM module
 */
impl<'a> Module<'a> for BM<'a> {

    fn exec(&self, matches: &ArgMatches) -> bool {
        match matches.subcommand_name() {
            Some("add") => {
                self.command_add(matches.subcommand_matches("add").unwrap())
            },

            Some("list") => {
                self.command_list(matches.subcommand_matches("list").unwrap())
            },

            Some("remove") => {
                self.command_remove(matches.subcommand_matches("remove").unwrap())
            },

            Some("add_tags") => {
                self.command_add_tags(matches.subcommand_matches("add_tags").unwrap())
            },

            Some("rm_tags") => {
                self.command_rm_tags(matches.subcommand_matches("rm_tags").unwrap())
            },

            Some("set_tags") => {
                self.command_set_tags(matches.subcommand_matches("set_tags").unwrap())
            },

            Some(_) | None => {
                info!("No command given, doing nothing");
                false
            },
        }
    }

    fn name(&self) -> &'static str {
        "bookmark"
    }
}

impl<'a> Debug for BM<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "BM");
        Ok(())
    }

}

<commit_msg>Auto merge of #36 - matthiasbeyer:bm-list-filter, r=matthiasbeyer<commit_after>use std::fmt::{Debug, Display, Formatter};
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt;
use std::ops::Deref;
use std::process::exit;

use clap::ArgMatches;
use regex::Regex;

use runtime::Runtime;
use module::Module;

use storage::Store;
use storage::file::hash::FileHash;
use storage::file::id::FileID;
use storage::file::File;
use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
use module::helpers::cli::get_file_filter_by_cli;
use module::helpers::cli::CliFileFilter;

mod header;

use self::header::get_url_from_header;
use self::header::get_tags_from_header;

pub struct BM<'a> {
    rt: &'a Runtime<'a>,
}

impl<'a> BM<'a> {

    pub fn new(rt: &'a Runtime<'a>) -> BM<'a> {
        BM {
            rt: rt,
        }
    }

    fn runtime(&self) -> &Runtime {
        &self.rt
    }

    /**
     * Subcommand: add
     */
    fn command_add(&self, matches: &ArgMatches) -> bool {
        use std::process::exit;
        use self::header::build_header;

        let parser = Parser::new(JsonHeaderParser::new(None));

        let url    = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present

        if !self.validate_url(&url, &parser) {
            error!("URL validation failed, exiting.");
            exit(1);
        } else {
            debug!("Verification succeeded");
        }

        let tags   = matches.value_of("tags").and_then(|s| {
            Some(s.split(",").map(String::from).collect())
        }).unwrap_or(vec![]);

        debug!("Building header with");
        debug!("    url  = '{:?}'", url);
        debug!("    tags = '{:?}'", tags);
        let header = build_header(url, tags);

        let fileid = self.rt.store().new_file_with_header(self, header);
        self.rt.store().load(&fileid).and_then(|file| {
            info!("Created file in memory: {}", fileid);
            Some(self.rt.store().persist(&parser, file))
        }).unwrap_or(false)
    }

    fn validate_url<HP>(&self, url: &String, parser: &Parser<HP>) -> bool
        where HP: FileHeaderParser
    {
        use util::is_url;

        if !is_url(url) {
            error!("Url '{}' is not a valid URL. Will not store.", url);
            return false;
        }

        let is_in_store = self.rt
            .store()
            .load_for_module(self, parser)
            .iter()
            .any(|file| {
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url_in_store| {
                    &url_in_store == url
                }).unwrap_or(false)
            });

        if is_in_store {
            error!("URL '{}' seems to be in the store already", url);
            return false;
        }

        return true;
    }

    /**
     * Subcommand: list
     */
    fn command_list(&self, matches: &ArgMatches) -> bool {
        use ui::file::{FilePrinter, TablePrinter};
        use std::ops::Deref;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser, matches, "id", "match", "tags", Some("URL"));

        let files  = self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file));
        let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());

        printer.print_files_custom(files,
            &|file| {
                let fl = file.deref().borrow();
                let hdr = fl.header();
                let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
                let tags = get_tags_from_header(hdr);

                debug!("Custom printer field: url  = '{:?}'", url);
                debug!("Custom printer field: tags = '{:?}'", tags);

                vec![url, tags.join(", ")]
            }
        );
        true
    }

    /**
     * Subcommand: remove
     */
    fn command_remove(&self, matches: &ArgMatches) -> bool {
        use std::process::exit;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser, matches, "id", "match", "tags", None);
        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can remove now: {:?}", file);
                let f = file.deref().borrow();
                self.rt.store().remove(f.id().clone())
            })
            .all(|x| x);

        if result {
            info!("Removing succeeded");
        } else {
            info!("Removing failed");
        }

        return result;
    }

    /**
     * Subcommand: add_tags
     */
    fn command_add_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            let mut new_tags = old_tags.clone();
            new_tags.append(&mut cli_tags.clone());
            new_tags
        })
    }

    /**
     * Subcommand: rm_tags
     */
    fn command_rm_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            old_tags.clone()
                .into_iter()
                .filter(|tag| !cli_tags.contains(tag))
                .collect()
        })
    }

    /**
     * Subcommand: set_tags
     */
    fn command_set_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            cli_tags.clone()
        })
    }

    /**
     * Helper function to alter the tags in a file
     */
    fn alter_tags_in_files<F>(&self, matches: &ArgMatches, generate_new_tags: F) -> bool
        where F: Fn(Vec<String>, &Vec<String>) -> Vec<String>
    {
        use self::header::rebuild_header_with_tags;

        let cli_tags = matches.value_of("tags")
                          .map(|ts| {
                            ts.split(",")
                              .map(String::from)
                              .collect::<Vec<String>>()
                          })
                          .unwrap_or(vec![]);

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser,
                                                                 matches,
                                                                 "with_id",
                                                                 "with_match",
                                                                 "with_tags",
                                                                 None);
        self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("Remove tags from file: {:?}", file);

                let hdr = {
                    let f = file.deref().borrow();
                    f.header().clone()
                };

                debug!("Tags:...");
                let old_tags = get_tags_from_header(&hdr);
                debug!("    old_tags = {:?}", &old_tags);
                debug!("    cli_tags = {:?}", &cli_tags);

                let new_tags = generate_new_tags(old_tags, &cli_tags);
                debug!("    new_tags = {:?}", &new_tags);

                let new_header = rebuild_header_with_tags(&hdr, new_tags)
                    .unwrap_or_else(|| {
                        error!("Could not rebuild header for file");
                        exit(1);
                    });
                {
                    let mut f_mut = file.deref().borrow_mut();
                    f_mut.set_header(new_header);
                }

                self.rt.store().persist(&parser, file);
                true
            })
            .all(|x| x)
    }

}

/**
 * Trait implementation for BM module
 */
impl<'a> Module<'a> for BM<'a> {

    fn exec(&self, matches: &ArgMatches) -> bool {
        match matches.subcommand_name() {
            Some("add") => {
                self.command_add(matches.subcommand_matches("add").unwrap())
            },

            Some("list") => {
                self.command_list(matches.subcommand_matches("list").unwrap())
            },

            Some("remove") => {
                self.command_remove(matches.subcommand_matches("remove").unwrap())
            },

            Some("add_tags") => {
                self.command_add_tags(matches.subcommand_matches("add_tags").unwrap())
            },

            Some("rm_tags") => {
                self.command_rm_tags(matches.subcommand_matches("rm_tags").unwrap())
            },

            Some("set_tags") => {
                self.command_set_tags(matches.subcommand_matches("set_tags").unwrap())
            },

            Some(_) | None => {
                info!("No command given, doing nothing");
                false
            },
        }
    }

    fn name(&self) -> &'static str {
        "bookmark"
    }
}

impl<'a> Debug for BM<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "BM");
        Ok(())
    }

}

<|endoftext|>


<commit_before>/* Copyright (c) 2014, Peter Nelson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#![crate_name = "jit"]
#![allow(raw_pointer_deriving, dead_code, non_camel_case_types, non_upper_case_globals, unknown_features)]
#![deny(unused_parens, unknown_lints, unreachable_code, unused_allocation, unused_allocation, unused_must_use)]
#![feature(globs, macro_rules, slicing_syntax, unboxed_closures, unsafe_destructor, phase)]
#![stable]
//! This crate wraps LibJIT in an idiomatic style.
//! For example, here's a quick example which makes a multiply function using LibJIT:
//!
//! ```rust
//! #![feature(phase)]
//! #[phase(link, plugin)]
//! extern crate jit;
//! use jit::{Context, get, Type};
//! fn main() {
//!     // make a new context to make functions on
//!     let mut ctx = Context::new();
//!     jit_func!(ctx, func, fn mul(x: int, y: int) -> int {
//!         let result = func.insn_mul(x, y);
//!         func.insn_return(&result);
//!     }, |mul| {
//!         assert_eq!(mul((4, 5)), 20);
//!     });
//! }
//! ```
extern crate libc;
#[cfg(test)]
extern crate test;
extern crate "libjit-sys" as raw;
use raw::{
    jit_init,
    jit_uses_interpreter,
    jit_supports_threads,
    jit_supports_virtual_memory
};
pub use raw::{
    jit_nint,
    jit_nuint
};
pub use compile::Compile;
pub use context::{Builder, Context};
pub use elf::*;
pub use function::{flags, UncompiledFunction, Function, CompiledFunction};
pub use function::flags::CallFlags;
pub use label::Label;
pub use types::kind::TypeKind;
pub use types::{kind, get, Type, Field, Fields, Params};
pub use util::NativeRef;
pub use value::Value;
use libc::{c_int, c_void};

/// Initialise the library and prepare for operations
#[inline]
pub fn init() -> () {
    unsafe {
        jit_init()
    }
}
/// Check if the JIT is using a fallback interpreter
#[inline]
pub fn uses_interpreter() -> bool {
    unsafe {
        jit_uses_interpreter() != 0
    }
}
/// Check if the JIT supports theads
#[inline]
pub fn supports_threads() -> bool {
    unsafe {
        jit_supports_threads() != 0
    }
}
/// Check if the JIT supports virtual memory
#[inline]
pub fn supports_virtual_memory() -> bool {
    unsafe {
        jit_supports_virtual_memory() != 0
    }
}

extern fn handle_exception(kind: c_int) -> *mut c_void {
    if kind == 1 {
        return ::std::ptr::null_mut();
    }
    panic!("{}", match kind {
        0 => "The operation resulted in an overflow exception",
        -1 => "The operation resulted in an arithmetic exception",
        -2 => "The operation resulted in a division by zero exception",
        -3 => "An error occurred when attempting to dynamically compile a function",
        -4 => "The system ran out of memory while performing an operation",
        -5 => "An attempt was made to dereference a NULL pointer",
        -6 => "An attempt was made to call a function with a NULL function pointer",
        -7 => "An attempt was made to call a nested function from a non-nested context",
        _ => "Unknown exception"
    });
}
#[macro_escape]
mod macros;
mod context;
mod compile;
mod elf;
mod function;
mod label;
#[cfg(test)]
mod tests;
mod types;
mod util;
mod value;<commit_msg>Export ABI of Function<commit_after>/* Copyright (c) 2014, Peter Nelson
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#![crate_name = "jit"]
#![allow(raw_pointer_deriving, dead_code, non_camel_case_types, non_upper_case_globals, unknown_features)]
#![deny(unused_parens, unknown_lints, unreachable_code, unused_allocation, unused_allocation, unused_must_use)]
#![feature(globs, macro_rules, slicing_syntax, unboxed_closures, unsafe_destructor, phase)]
#![stable]
//! This crate wraps LibJIT in an idiomatic style.
//! For example, here's a quick example which makes a multiply function using LibJIT:
//!
//! ```rust
//! #![feature(phase)]
//! #[phase(link, plugin)]
//! extern crate jit;
//! use jit::{Context, get, Type};
//! fn main() {
//!     // make a new context to make functions on
//!     let mut ctx = Context::new();
//!     jit_func!(ctx, func, fn mul(x: int, y: int) -> int {
//!         let result = func.insn_mul(x, y);
//!         func.insn_return(&result);
//!     }, |mul| {
//!         assert_eq!(mul((4, 5)), 20);
//!     });
//! }
//! ```
extern crate libc;
#[cfg(test)]
extern crate test;
extern crate "libjit-sys" as raw;
use raw::{
    jit_init,
    jit_uses_interpreter,
    jit_supports_threads,
    jit_supports_virtual_memory
};
pub use raw::{
    jit_nint,
    jit_nuint
};
pub use compile::Compile;
pub use context::{Builder, Context};
pub use elf::*;
pub use function::{flags, ABI, UncompiledFunction, Function, CompiledFunction};
pub use function::flags::CallFlags;
pub use label::Label;
pub use types::kind::TypeKind;
pub use types::{kind, get, Type, Field, Fields, Params};
pub use util::NativeRef;
pub use value::Value;
use libc::{c_int, c_void};

/// Initialise the library and prepare for operations
#[inline]
pub fn init() -> () {
    unsafe {
        jit_init()
    }
}
/// Check if the JIT is using a fallback interpreter
#[inline]
pub fn uses_interpreter() -> bool {
    unsafe {
        jit_uses_interpreter() != 0
    }
}
/// Check if the JIT supports theads
#[inline]
pub fn supports_threads() -> bool {
    unsafe {
        jit_supports_threads() != 0
    }
}
/// Check if the JIT supports virtual memory
#[inline]
pub fn supports_virtual_memory() -> bool {
    unsafe {
        jit_supports_virtual_memory() != 0
    }
}

extern fn handle_exception(kind: c_int) -> *mut c_void {
    if kind == 1 {
        return ::std::ptr::null_mut();
    }
    panic!("{}", match kind {
        0 => "The operation resulted in an overflow exception",
        -1 => "The operation resulted in an arithmetic exception",
        -2 => "The operation resulted in a division by zero exception",
        -3 => "An error occurred when attempting to dynamically compile a function",
        -4 => "The system ran out of memory while performing an operation",
        -5 => "An attempt was made to dereference a NULL pointer",
        -6 => "An attempt was made to call a function with a NULL function pointer",
        -7 => "An attempt was made to call a nested function from a non-nested context",
        _ => "Unknown exception"
    });
}
#[macro_escape]
mod macros;
mod context;
mod compile;
mod elf;
mod function;
mod label;
#[cfg(test)]
mod tests;
mod types;
mod util;
mod value;<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::io::fs::File;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    history: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let writeRedirect = cmd_line.find_str(" > ");
            let readRedirect = cmd_line.find_str(" < ");
            if(writeRedirect == None && readRedirect == None) {
            	let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            	self.history.push(cmd_line.clone());
            	match cmd_line.slice_from(cmd_line.len() - 2) {
            		" &"    => { self.run_background(program, cmd_line);
            			continue; }
                	_	=> { }
            	}
            	match program {
			""           =>  { continue; }
			"exit"       =>  { return; }
			"cd"	     =>  { self.run_cd(cmd_line); }
			"history"    =>  { self.run_history(); }
			_            =>  { self.run_cmdline(cmd_line); }
            	}
            }
            else if (readRedirect == None) {
            	let cmd1 = cmd_line.slice(0, writeRedirect.unwrap());
            	let cmd2 = cmd_line.slice_from(writeRedirect.unwrap()+3);
            	let program = cmd1.splitn(' ', 1).nth(0).expect("no program");
            	let args : ~[&str] = cmd1.splitn(' ', 1).nth(1).unwrap().split(' ').collect();
            	let mut argsOwned : ~[~str] = ~[];
            	for i in range (0, args.len()) {
            		argsOwned.push(args[i].to_owned());
            	}
		let newStdOut = File::create(&Path::new(cmd2));
            	match newStdOut {
            		Some(mut x) => {
            			let process = run::Process::new(program, argsOwned, run::ProcessOptions::new());
            			let output = process.unwrap().finish_with_output();
            			x.write(output.output);
            		}
            		None => { println("shouldnt be here");}
            	}
            }
            else if (writeRedirect == None) {
            	let cmd1 = cmd_line.slice(0, readRedirect.unwrap());
            	let cmd2 = cmd_line.slice_from(readRedirect.unwrap()+3);
            	let program = cmd1.splitn(' ', 1).nth(0).expect("no program");
            	let args : ~[&str] = cmd1.splitn(' ', 1).nth(1).unwrap().split(' ').collect();
            	let mut argsOwned : ~[~str] = ~[];
            	for i in range (0, args.len()) {
            		argsOwned.push(args[i].to_owned());
            	}
		let input = File::create(&Path::new(cmd2));
            	match input {
            		Some(mut x) => {
            			let inputBytes = x.read_to_end();
            			let process = run::Process::new(program, argsOwned, run::ProcessOptions::new());
            			process.unwrap().input().write(inputBytes);
            		}
            		None => { println!("gash: {:s}: No such file or directory", cmd2);}
            	}
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cd(&mut self, program: &str) {
        let mut argv: ~[~str] =
            program.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

    	let mut programs : ~str = ~"";
            if argv.len() > 0 {
                programs = argv.remove(1);
            }
    	os::change_dir(&Path::new(programs.clone()));
    }

    fn run_history(&mut self) {
        for c in range(0, self.history.len()) {
            println!("{:s}", self.history[c]);
        }
    }

    fn run_background(&mut self, program: &str, cmd_line: &str) {
		let (portSelf, chanSelf): (Port<~Shell>, Chan<~Shell>) = Chan::new();
		let (portProg, chanProg): (Port<~str>, Chan<~str>) = Chan::new();
		let (portLine, chanLine): (Port<~str>, Chan<~str>) = Chan::new();

		chanSelf.send(~(Shell::new("gash > ")));
		chanProg.send(program.to_owned());
		chanLine.send(cmd_line.to_owned());
            do spawn {
		let program : ~str = portProg.recv();
		let cmd_line : ~str = portLine.recv();
		let mut selfV : ~Shell = portSelf.recv();
                match program {
             	   ~""           =>  { }
              	  ~"exit"       =>  { }
		  ~"cd"	     =>  { selfV.run_cd(cmd_line); }
                  ~"history"    =>  { selfV.run_history(); }
                  _            =>  { selfV.run_cmdline(cmd_line); }
                }
            };
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>< now works when the file is present<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os, str};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::io::fs::File;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    history: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let writeRedirect = cmd_line.find_str(" > ");
            let readRedirect = cmd_line.find_str(" < ");
            if(writeRedirect == None && readRedirect == None) {
            	let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            	self.history.push(cmd_line.clone());
            	match cmd_line.slice_from(cmd_line.len() - 2) {
            		" &"    => { self.run_background(program, cmd_line);
            			continue; }
                	_	=> { }
            	}
            	match program {
			""           =>  { continue; }
			"exit"       =>  { return; }
			"cd"	     =>  { self.run_cd(cmd_line); }
			"history"    =>  { self.run_history(); }
			_            =>  { self.run_cmdline(cmd_line); }
            	}
            }
            else if (readRedirect == None) {
            	let cmd1 = cmd_line.slice(0, writeRedirect.unwrap());
            	let cmd2 = cmd_line.slice_from(writeRedirect.unwrap()+3);
            	let program = cmd1.splitn(' ', 1).nth(0).expect("no program");
            	let args : ~[&str] = if (cmd1.splitn(' ', 1).nth(1) != None) {cmd1.splitn(' ', 1).nth(1).unwrap().split(' ').collect()} else {~[]};
            	let mut argsOwned : ~[~str] = ~[];
            	for i in range (0, args.len()) {
            		argsOwned.push(args[i].to_owned());
            	}
		let newStdOut = File::create(&Path::new(cmd2));
            	match newStdOut {
            		Some(mut x) => {
            			let process = run::Process::new(program, argsOwned, run::ProcessOptions::new());
            			let output = process.unwrap().finish_with_output();
            			x.write(output.output);
            		}
            		None => { println("shouldnt be here");}
            	}
            }
            else if (writeRedirect == None) {
            	let cmd1 = cmd_line.slice(0, readRedirect.unwrap());
            	let cmd2 = cmd_line.slice_from(readRedirect.unwrap()+3);
            	let program = cmd1.splitn(' ', 1).nth(0).expect("no program");
            	let args : ~[&str] = if (cmd1.splitn(' ', 1).nth(1) != None) {cmd1.splitn(' ', 1).nth(1).unwrap().split(' ').collect()} else {~[]};
            	let mut argsOwned : ~[~str] = ~[];
            	for i in range (0, args.len()) {
            		argsOwned.push(args[i].to_owned());
            	}
		let input = File::open(&Path::new(cmd2));
            	match input {
            		Some(mut x) => {
            			let inputBytes = x.read_to_end();
            			let process = run::Process::new(program, argsOwned, run::ProcessOptions::new());
            			match(process) {
            				Some(mut toWrite) => {
            					toWrite.input().write(inputBytes);
            					let output = toWrite.finish_with_output();
            					print!("{:s}", str::from_utf8(output.output));
            				}
            				None => {}
        			}
            		}
            		None => { println!("gash: {:s}: No such file or directory", cmd2);}
            	}
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cd(&mut self, program: &str) {
        let mut argv: ~[~str] =
            program.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

    	let mut programs : ~str = ~"";
            if argv.len() > 0 {
                programs = argv.remove(1);
            }
    	os::change_dir(&Path::new(programs.clone()));
    }

    fn run_history(&mut self) {
        for c in range(0, self.history.len()) {
            println!("{:s}", self.history[c]);
        }
    }

    fn run_background(&mut self, program: &str, cmd_line: &str) {
		let (portSelf, chanSelf): (Port<~Shell>, Chan<~Shell>) = Chan::new();
		let (portProg, chanProg): (Port<~str>, Chan<~str>) = Chan::new();
		let (portLine, chanLine): (Port<~str>, Chan<~str>) = Chan::new();

		chanSelf.send(~(Shell::new("gash > ")));
		chanProg.send(program.to_owned());
		chanLine.send(cmd_line.to_owned());
            do spawn {
		let program : ~str = portProg.recv();
		let cmd_line : ~str = portLine.recv();
		let mut selfV : ~Shell = portSelf.recv();
                match program {
             	   ~""           =>  { }
              	  ~"exit"       =>  { }
		  ~"cd"	     =>  { selfV.run_cd(cmd_line); }
                  ~"history"    =>  { selfV.run_history(); }
                  _            =>  { selfV.run_cmdline(cmd_line); }
                }
            };
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>/// Key is used by the get key functions to check if some keys on the keyboard has been pressed
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Key {
    Key0 = 0,
    Key1 = 1,
    Key2 = 2,
    Key3 = 3,
    Key4 = 4,
    Key5 = 5,
    Key6 = 6,
    Key7 = 7,
    Key8 = 8,
    Key9 = 9,

    A = 10,
    B = 11,
    C = 12,
    D = 13,
    E = 14,
    F = 15,
    G = 16,
    H = 17,
    I = 18,
    J = 19,
    K = 20,
    L = 21,
    M = 22,
    N = 23,
    O = 24,
    P = 25,
    Q = 26,
    R = 27,
    S = 28,
    T = 29,
    U = 30,
    V = 31,
    W = 32,
    X = 33,
    Y = 34,
    Z = 35,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,

    Down,
    Left,
    Right,
    Up,
    Apostrophe,
    Backquote,

    Backslash,
    Comma,
    Equal,
    LeftBracket,
    Minus,
    Period,
    RightBracket,
    Semicolon,

    Slash,
    Backspace,
    Delete,
    End,
    Enter,

    Escape,

    Home,
    Insert,
    Menu,

    PageDown,
    PageUp,

    Pause,
    Space,
    Tab,
    NumLock,
    CapsLock,
    ScrollLock,
    LeftShift,
    RightShift,
    LeftCtrl,
    RightCtrl,

    NumPad0,
    NumPad1,
    NumPad2,
    NumPad3,
    NumPad4,
    NumPad5,
    NumPad6,
    NumPad7,
    NumPad8,
    NumPad9,
    NumPadDot,
    NumPadSlash,
    NumPadAsterisk,
    NumPadMinus,
    NumPadPlus,
    NumPadEnter,

    LeftAlt,
    RightAlt,

    LeftSuper,
    RightSuper,

    /// Used when an Unknown key has been pressed
    Unknown,

    Count = 107,
}

<commit_msg>Add additional derived traits to Key enum (#65)<commit_after>/// Key is used by the get key functions to check if some keys on the keyboard has been pressed
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
pub enum Key {
    Key0 = 0,
    Key1 = 1,
    Key2 = 2,
    Key3 = 3,
    Key4 = 4,
    Key5 = 5,
    Key6 = 6,
    Key7 = 7,
    Key8 = 8,
    Key9 = 9,

    A = 10,
    B = 11,
    C = 12,
    D = 13,
    E = 14,
    F = 15,
    G = 16,
    H = 17,
    I = 18,
    J = 19,
    K = 20,
    L = 21,
    M = 22,
    N = 23,
    O = 24,
    P = 25,
    Q = 26,
    R = 27,
    S = 28,
    T = 29,
    U = 30,
    V = 31,
    W = 32,
    X = 33,
    Y = 34,
    Z = 35,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,

    Down,
    Left,
    Right,
    Up,
    Apostrophe,
    Backquote,

    Backslash,
    Comma,
    Equal,
    LeftBracket,
    Minus,
    Period,
    RightBracket,
    Semicolon,

    Slash,
    Backspace,
    Delete,
    End,
    Enter,

    Escape,

    Home,
    Insert,
    Menu,

    PageDown,
    PageUp,

    Pause,
    Space,
    Tab,
    NumLock,
    CapsLock,
    ScrollLock,
    LeftShift,
    RightShift,
    LeftCtrl,
    RightCtrl,

    NumPad0,
    NumPad1,
    NumPad2,
    NumPad3,
    NumPad4,
    NumPad5,
    NumPad6,
    NumPad7,
    NumPad8,
    NumPad9,
    NumPadDot,
    NumPadSlash,
    NumPadAsterisk,
    NumPadMinus,
    NumPadPlus,
    NumPadEnter,

    LeftAlt,
    RightAlt,

    LeftSuper,
    RightSuper,

    /// Used when an Unknown key has been pressed
    Unknown,

    Count = 107,
}

<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                _       =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>history function added<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    log:        ~[~str],
}

impl Shell {

    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            log: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "exit"  =>  { return; }
                "history" => {
                    self.log.push(cmd_line.to_owned());
                    self.run_history();
                }
                "cd" => {
                    self.log.push(cmd_line.to_owned());
                    self.run_cd(cmd_line.to_owned());
                }
                _       =>  {
                    self.log.push(cmd_line.to_owned());
                    self.run_cmdline(cmd_line);
                }
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_history(&mut self){
        for i in range(0, self.log.len()) {
            println!("{}", self.log[i]);
        }
    }

    fn run_cd(&mut self, cmd_line: &str) {}
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;
use std::io::File;
use std::io::signal::{Listener, Interrupt};

struct Shell {
    cmd_prompt: ~str,
    log:        ~[~str],
}

impl Shell {

    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            log: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt); // prints 'gash >'
            io::stdio::flush();

            let line = stdin.read_line().unwrap(); // reads whats on the line
            let cmd_line = line.trim().to_owned();  // removes leading and trailing whitespace
            let user_input: ~[&str] = cmd_line.split(' ').collect();
            let mut line: ~str = ~"";
            let length: uint = user_input.len();
            let mut i : uint = 0;

            while (i < length){

                let string = user_input[i].clone();
                let mut input = ~"";
                match string {

                    "<" => {
                        if !(i < length-1)
                            {println!("invalid command");}

                        let file  = user_input[i+1].to_owned(); // get file name
                        let command = line.trim().to_owned();
                        line = command + " " + file;
                        i += 1;
                    }

                    ">" => {
                        if !(i < length-1)
                            {println!("invalid command");}

			            let file = user_input[i + 1].to_owned();
			            let command = line.trim().to_owned();
			            let message = self.find_prog(command, true).to_owned();

                        if message == ~"none"{
                            i = length;
                        }

                        write_file(file,message);
                        line = ~"";
                        i += 1;
                    }

                    "|" => {

                        let command = line.trim().to_owned();
                        let mut command2: ~str = ~"";

                        for k in range(i + 1,length){
                            match user_input[k]{
                                "<" => {break;}
                                ">" =>{break;}
                                "|" => {break;}
                                _   => {command2 = command2 + " " + user_input[k];}
                            }
                            i = k;
                        }

                        command2 = command2.trim().to_owned();
                        let mut message = self.find_prog(command, true).to_owned();

                        if message == ~"none"{
                            i = length;
                        }

                        match File::create(&Path::new("f.md")) {
                            Some(mut file) => {
                                file.write_str(message);
                            }
                            None =>{
                                println("Opening file failed!");
                            }
                        }

                        //println(command2);
                        message = self.find_prog(command2 + " " + "f.md", true).to_owned();
                        self.find_prog("rm f.md", true);
                        println!("{}", message);
                        line = ~"";
                    }

                    _ => {
                        line = line + " " + string;
                    }
                }
                i += 1;
            }

            let result = self.find_prog(line.trim(),false);
            match result {
                ~"return" => {
                    println("exit pls");
                    return;}
                //~"continue" => {continue;}
                _          => {}
            }
        }
    }

    fn find_prog(&mut self, cmd_line : &str, output: bool) -> ~str{
         let program = cmd_line.splitn(' ', 1).nth(0).expect("no program"); // get command

         match program {
                ""      =>  { return ~"continue"; }
                "exit"  =>  { return ~"return"; }
                "history" => {
                    self.log.push(cmd_line.to_owned());
                    return self.run_history(output);
                }
                "cd" => {
                    self.log.push(cmd_line.to_owned());
                    self.run_cd(cmd_line);
                }
                _       =>  {
                    self.log.push(cmd_line.to_owned());
                    return self.run_cmdline(cmd_line, output);
                }
            }
        ~"fine"
    }

    fn run_cmdline(&mut self, cmd_line: &str, output: bool) -> ~str {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

	let length = argv.len()-1;

    	if argv[length] == ~"&" {
	    argv.remove(length);
            let program: ~str = argv.remove(0);
	    let argv2 = argv.clone();

	    if self.cmd_exists(program){

		spawn(proc() {run::process_status(program, argv2);});

	    }
            else {
		println!("{:s}: command not found", program);
            }

	return ~"none";
	}

	else{
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            return self.run_cmd(program, argv, output);
        }
	}
	return ~"none";
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str], output: bool)->~str {
        if self.cmd_exists(program) {
	    if output == false {
            run::process_status(program, argv);
	    return ~"none";
	    }
	    else {
	    	let output = run::process_output(program, argv);
	  	let output_str = output.unwrap().output;
		return std::str::from_utf8(output_str).to_owned();
	    }
        } else {
            println!("{:s}: command not found", program);
        }
	return ~"none";
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_history(&mut self, output: bool)-> ~str{
	if output == false{
        	for i in range(0, self.log.len()) {
            		println!("{}", self.log[i]);
        	}
		return ~"none";
	}
	else {
		let mut out: ~str = ~"";
		for i in range(0, self.log.len()){
			out = out + self.log[i].to_owned();
		}
		return out;
	}
    }

    fn run_cd(&mut self, cmd_line: &str) {
         let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {

            if argv.len() == 1 {
                self.go_to_home_dir();
                return ;
            }

            let string: ~str = argv.remove(1);
            if string == ~"$HOME" || string == ~"$home"{
                self.go_to_home_dir();
                return ;
            }
            let path = ~Path::new(string);
            if (path.exists()){
                let success = std::os::change_dir(path);
                if !success {
                    println("Invalid path");
                }
            }
        }
        else {
            println("Invalid input");
        }
    }

    fn go_to_home_dir(&mut self){
        match std::os::homedir() {
            Some(path) => {
                    std::os::change_dir(&path);
               }
             None => {
                    println("$HOME is not set");
               }
         }
    }

}

fn write_file(filename: ~str, message: ~str){

    match File::create(&Path::new(filename)) {
        Some(mut file) => {
            file.write_str(message);
        }
        None =>{
            println("Opening file failed!");
        }
    }
}

/*
fn read_file(filename: ~str) -> ~str{

    let path = Path::new(filename);
    match File::open(&path) {
        Some(file) => {
            let mut reader = BufferedReader::new(file);
            let input = reader.read_to_str();
            return input;
        }
        None =>{
            println("Opening file failed");
            return ~"";
        }
    }
}
*/

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    spawn(proc () {
    let mut listener = Listener::new();
        listener.register(Interrupt);
    loop{
        match listener.port.recv() {
            Interrupt => print!(""),
            _ => (),
        }
    }
   });

    match opt_cmd_line {
        Some(cmd_line) => {Shell::new("").run_cmdline(cmd_line, false);}
        None           => {Shell::new("gash > ").run();}
    }
}
<commit_msg>Fixed bug with "exit" command<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;
use std::io::File;
use std::io::signal::{Listener, Interrupt};
use std::libc;

struct Shell {
    cmd_prompt: ~str,
    log:        ~[~str],
}

impl Shell {

    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            log: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt); // prints 'gash >'
            io::stdio::flush();

            let line = stdin.read_line().unwrap(); // reads whats on the line
            let cmd_line = line.trim().to_owned();  // removes leading and trailing whitespace
            let user_input: ~[&str] = cmd_line.split(' ').collect();
            let mut line: ~str = ~"";
            let length: uint = user_input.len();
            let mut i : uint = 0;

            while (i < length){

                let string = user_input[i].clone();
                let mut input = ~"";
                match string {

                    "<" => {
                        if !(i < length-1)
                            {println!("invalid command");}

                        let file  = user_input[i+1].to_owned(); // get file name
                        let command = line.trim().to_owned();
                        line = command + " " + file;
                        i += 1;
                    }

                    ">" => {
                        if !(i < length-1)
                            {println!("invalid command");}

			            let file = user_input[i + 1].to_owned();
			            let command = line.trim().to_owned();
			            let message = self.find_prog(command, true).to_owned();

                        if message == ~"none"{
                            i = length;
                        }

                        write_file(file,message);
                        line = ~"";
                        i += 1;
                    }

                    "|" => {

                        let command = line.trim().to_owned();
                        let mut command2: ~str = ~"";

                        for k in range(i + 1,length){
                            match user_input[k]{
                                "<" => {break;}
                                ">" =>{break;}
                                "|" => {break;}
                                _   => {command2 = command2 + " " + user_input[k];}
                            }
                            i = k;
                        }

                        command2 = command2.trim().to_owned();
                        let mut message = self.find_prog(command, true).to_owned();

                        if message == ~"none"{
                            i = length;
                        }

                        match File::create(&Path::new("f.md")) {
                            Some(mut file) => {
                                file.write_str(message);
                            }
                            None =>{
                                println("Opening file failed!");
                            }
                        }

                        //println(command2);
                        message = self.find_prog(command2 + " " + "f.md", true).to_owned();
                        self.find_prog("rm f.md", true);
                        println!("{}", message);
                        line = ~"";
                    }

                    _ => {
                        line = line + " " + string;
                    }
                }
                i += 1;
            }

            let result = self.find_prog(line.trim(),false);
            match result {
                ~"return" => {unsafe{libc::exit(1 as libc::c_int)}}
                //~"continue" => {continue;}
                _          => {}
            }
        }
    }

    fn find_prog(&mut self, cmd_line : &str, output: bool) -> ~str{
         let program = cmd_line.splitn(' ', 1).nth(0).expect("no program"); // get command

         match program {
                ""      =>  { return ~"continue"; }
                "exit"  =>  { return ~"return"; }
                "history" => {
                    self.log.push(cmd_line.to_owned());
                    return self.run_history(output);
                }
                "cd" => {
                    self.log.push(cmd_line.to_owned());
                    self.run_cd(cmd_line);
                }
                _       =>  {
                    self.log.push(cmd_line.to_owned());
                    return self.run_cmdline(cmd_line, output);
                }
            }
        ~"fine"
    }

    fn run_cmdline(&mut self, cmd_line: &str, output: bool) -> ~str {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

	let length = argv.len()-1;

    	if argv[length] == ~"&" {
	    argv.remove(length);
            let program: ~str = argv.remove(0);
	    let argv2 = argv.clone();

	    if self.cmd_exists(program){

		spawn(proc() {run::process_status(program, argv2);});

	    }
            else {
		println!("{:s}: command not found", program);
            }

	return ~"none";
	}

	else{
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            return self.run_cmd(program, argv, output);
        }
	}
	return ~"none";
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str], output: bool)->~str {
        if self.cmd_exists(program) {
	    if output == false {
            run::process_status(program, argv);
	    return ~"none";
	    }
	    else {
	    	let output = run::process_output(program, argv);
	  	let output_str = output.unwrap().output;
		return std::str::from_utf8(output_str).to_owned();
	    }
        } else {
            println!("{:s}: command not found", program);
        }
	return ~"none";
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_history(&mut self, output: bool)-> ~str{
	if output == false{
        	for i in range(0, self.log.len()) {
            		println!("{}", self.log[i]);
        	}
		return ~"none";
	}
	else {
		let mut out: ~str = ~"";
		for i in range(0, self.log.len()){
			out = out + self.log[i].to_owned();
		}
		return out;
	}
    }

    fn run_cd(&mut self, cmd_line: &str) {
         let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {

            if argv.len() == 1 {
                self.go_to_home_dir();
                return ;
            }

            let string: ~str = argv.remove(1);
            if string == ~"$HOME" || string == ~"$home"{
                self.go_to_home_dir();
                return ;
            }
            let path = ~Path::new(string);
            if (path.exists()){
                let success = std::os::change_dir(path);
                if !success {
                    println("Invalid path");
                }
            }
        }
        else {
            println("Invalid input");
        }
    }

    fn go_to_home_dir(&mut self){
        match std::os::homedir() {
            Some(path) => {
                    std::os::change_dir(&path);
               }
             None => {
                    println("$HOME is not set");
               }
         }
    }

}

fn write_file(filename: ~str, message: ~str){

    match File::create(&Path::new(filename)) {
        Some(mut file) => {
            file.write_str(message);
        }
        None =>{
            println("Opening file failed!");
        }
    }
}

/*
fn read_file(filename: ~str) -> ~str{

    let path = Path::new(filename);
    match File::open(&path) {
        Some(file) => {
            let mut reader = BufferedReader::new(file);
            let input = reader.read_to_str();
            return input;
        }
        None =>{
            println("Opening file failed");
            return ~"";
        }
    }
}
*/

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    spawn(proc () {
    let mut listener = Listener::new();
        listener.register(Interrupt);
    loop{
        match listener.port.recv() {
            Interrupt => print!(""),
            _ => (),
        }
    }
   });

    match opt_cmd_line {
        Some(cmd_line) => {Shell::new("").run_cmdline(cmd_line, false);}
        None           => {Shell::new("gash > ").run();}
    }
}
<|endoftext|>