<commit_before>//! Provides SDK Information
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};

use zip;
use walkdir;
use memmap;
use regex::Regex;

use super::{Result, Error, ErrorKind};
use super::dsym::Object;

enum ObjectIterSource {
    Zip {
        archive: zip::ZipArchive<fs::File>,
        idx: usize,
    },
    Dir {
        dir_iter: walkdir::Iter,
    }
}

fn get_sdk_name_from_folder(folder: &str) -> Option<&'static str> {
    match folder {
        "iOS DeviceSupport" => Some("iOS"),
        "tvOS DeviceSupport" => Some("tvOS"),
        _ => None,
    }
}

/// Information of the SDK
#[derive(Debug)]
pub struct SdkInfo {
    /// The name of the SDK (iOS, tvOS etc.)
    pub name: &'static str,
    /// The major version identifier
    pub version_major: u32,
    /// The minor version identifier
    pub version_minor: u32,
    /// The patchlevel version identifier (might be 0)
    pub version_patchlevel: u32,
    /// build number.
    pub build: String,
    /// The SDK flavour (this is currently only used for watchOS)
    /// where this can be `Watch2,2` for instance.
    pub flavour: Option<String>,
}

pub struct ObjectsIter<'a> {
    info: &'a SdkInfo,
    source: ObjectIterSource,
}

pub struct SdkProcessor {
    path: PathBuf,
    info: SdkInfo,
}

impl SdkInfo {

    /// Load an SDK info from a given path
    ///
    /// If the parse cannot be parsed for an SDK info `None` is returned.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Option<SdkInfo> {
        lazy_static! {
            static ref SDK_FILENAME_RE: Regex = Regex::new(r"(?x)
                ^
                    (\d+)\.(\d+)(?:\.(\d+))?
                    \s+
                    \(([a-zA-Z0-9]+)\)
                    (?:\.zip)?
                $
            ").unwrap();
        }

        let p = path.as_ref();
        let folder = try_opt!(p.parent().and_then(|x| x.file_name()).and_then(|x| x.to_str()));
        let filename = try_opt!(p.file_name().and_then(|x| x.to_str()));
        let caps = try_opt!(SDK_FILENAME_RE.captures(filename));
        Some(SdkInfo {
            name: try_opt!(get_sdk_name_from_folder(folder)),
            version_major: try_opt!(caps.get(1).unwrap().as_str().parse().ok()),
            version_minor: try_opt!(caps.get(2).unwrap().as_str().parse().ok()),
            version_patchlevel: try_opt!(caps.get(3).map(|x| x.as_str()).unwrap_or("0").parse().ok()),
            build: try_opt!(caps.get(4).map(|x| x.as_str().to_string())),
            flavour: None,
        })
    }
}

impl ObjectIterSource {
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<ObjectIterSource> {
        let md = fs::metadata(path.as_ref())?;
        if md.is_file() {
            let f = fs::File::open(path.as_ref())?;
            let zip = zip::ZipArchive::new(f)?;
            Ok(ObjectIterSource::Zip {
                archive: zip,
                idx: 0,
            })
        } else {
            Ok(ObjectIterSource::Dir {
                dir_iter: walkdir::WalkDir::new(path.as_ref()).into_iter(),
            })
        }
    }
}

impl<'a> Iterator for ObjectsIter<'a> {
    type Item = Result<Object<'a>>;

    fn next(&mut self) -> Option<Result<Object<'a>>> {
        loop {
            match self.source {
                ObjectIterSource::Zip { ref mut archive, ref mut idx } => {
                    if *idx >= archive.len() {
                        break;
                    }
                    let mut f = iter_try!(archive.by_index(*idx));
                    *idx += 1;
                    let mut buf : Vec<u8> = vec![];
                    iter_try!(f.read_to_end(&mut buf));
                    return Some(Ok(iter_try!(Object::from_vec(buf))));
                }
                ObjectIterSource::Dir { ref mut dir_iter } => {
                    if let Some(dent_res) = dir_iter.next() {
                        let dent = iter_try!(dent_res);
                        let md = iter_try!(dent.metadata());
                        if md.is_file() {
                            return Some(Ok(iter_try!(Object::from_path(dent.path()))));
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        None
    }
}

impl SdkProcessor {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<SdkProcessor> {
        let p = path.as_ref().to_path_buf();
        let sdk_info = SdkInfo::from_path(&p).ok_or_else(|| {
            Error::from(ErrorKind::UnknownSdk)
        })?;
        Ok(SdkProcessor {
            path: p,
            info: sdk_info,
        })
    }

    pub fn objects<'a>(&'a self) -> Result<ObjectsIter<'a>> {
        Ok(ObjectsIter {
            info: &self.info,
            source: ObjectIterSource::from_path(&self.path)?,
        })
    }
}
<commit_msg>Improve reporting from object iterator<commit_after>//! Provides SDK Information
use std::fs;
use std::io::Read;
use std::path::{Path, PathBuf};

use zip;
use walkdir;
use regex::Regex;
use mach_object::Error as MachError;

use super::{Result, Error, ErrorKind};
use super::dsym::Object;

enum ObjectIterSource {
    Zip {
        archive: zip::ZipArchive<fs::File>,
        idx: usize,
    },
    Dir {
        dir_iter: walkdir::Iter,
    }
}

fn get_sdk_name_from_folder(folder: &str) -> Option<&'static str> {
    match folder {
        "iOS DeviceSupport" => Some("iOS"),
        "tvOS DeviceSupport" => Some("tvOS"),
        _ => None,
    }
}

/// Information of the SDK
#[derive(Debug)]
pub struct SdkInfo {
    /// The name of the SDK (iOS, tvOS etc.)
    pub name: &'static str,
    /// The major version identifier
    pub version_major: u32,
    /// The minor version identifier
    pub version_minor: u32,
    /// The patchlevel version identifier (might be 0)
    pub version_patchlevel: u32,
    /// build number.
    pub build: String,
    /// The SDK flavour (this is currently only used for watchOS)
    /// where this can be `Watch2,2` for instance.
    pub flavour: Option<String>,
}

pub struct ObjectsIter {
    source: ObjectIterSource,
}

pub struct SdkProcessor {
    path: PathBuf,
    info: SdkInfo,
}

impl SdkInfo {

    /// Load an SDK info from a given path
    ///
    /// If the parse cannot be parsed for an SDK info `None` is returned.
    pub fn from_path<P: AsRef<Path>>(path: P) -> Option<SdkInfo> {
        lazy_static! {
            static ref SDK_FILENAME_RE: Regex = Regex::new(r"(?x)
                ^
                    (\d+)\.(\d+)(?:\.(\d+))?
                    \s+
                    \(([a-zA-Z0-9]+)\)
                    (?:\.zip)?
                $
            ").unwrap();
        }

        let p = path.as_ref();
        let folder = try_opt!(p.parent().and_then(|x| x.file_name()).and_then(|x| x.to_str()));
        let filename = try_opt!(p.file_name().and_then(|x| x.to_str()));
        let caps = try_opt!(SDK_FILENAME_RE.captures(filename));
        Some(SdkInfo {
            name: try_opt!(get_sdk_name_from_folder(folder)),
            version_major: try_opt!(caps.get(1).unwrap().as_str().parse().ok()),
            version_minor: try_opt!(caps.get(2).unwrap().as_str().parse().ok()),
            version_patchlevel: try_opt!(caps.get(3).map(|x| x.as_str()).unwrap_or("0").parse().ok()),
            build: try_opt!(caps.get(4).map(|x| x.as_str().to_string())),
            flavour: None,
        })
    }
}

impl ObjectIterSource {
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<ObjectIterSource> {
        let md = fs::metadata(path.as_ref())?;
        if md.is_file() {
            let f = fs::File::open(path.as_ref())?;
            let zip = zip::ZipArchive::new(f)?;
            Ok(ObjectIterSource::Zip {
                archive: zip,
                idx: 0,
            })
        } else {
            Ok(ObjectIterSource::Dir {
                dir_iter: walkdir::WalkDir::new(path.as_ref()).into_iter(),
            })
        }
    }
}

impl<'a> Iterator for ObjectsIter {
    type Item = Result<Object<'static>>;

    fn next(&mut self) -> Option<Result<Object<'static>>> {
        macro_rules! try_return_obj {
            ($expr:expr) => {
                match $expr {
                    Ok(rv) => {
                        return Some(Ok(rv));
                    }
                    Err(err) => {
                        if let &ErrorKind::MachO(ref mach_err) = err.kind() {
                            if let &MachError::LoadError(_) = mach_err {
                                continue;
                            }
                        }
                        return Some(Err(err.into()));
                    }
                }
            }
        }

        loop {
            match self.source {
                ObjectIterSource::Zip { ref mut archive, ref mut idx } => {
                    if *idx >= archive.len() {
                        break;
                    }
                    let mut f = iter_try!(archive.by_index(*idx));
                    *idx += 1;
                    let mut buf : Vec<u8> = vec![];
                    iter_try!(f.read_to_end(&mut buf));
                    try_return_obj!(Object::from_vec(buf));
                }
                ObjectIterSource::Dir { ref mut dir_iter } => {
                    if let Some(dent_res) = dir_iter.next() {
                        let dent = iter_try!(dent_res);
                        let md = iter_try!(dent.metadata());
                        if md.is_file() && md.len() > 0 {
                            try_return_obj!(Object::from_path(dent.path()));
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        None
    }
}

impl SdkProcessor {
    pub fn new<P: AsRef<Path>>(path: P) -> Result<SdkProcessor> {
        let p = path.as_ref().to_path_buf();
        let sdk_info = SdkInfo::from_path(&p).ok_or_else(|| {
            Error::from(ErrorKind::UnknownSdk)
        })?;
        Ok(SdkProcessor {
            path: p,
            info: sdk_info,
        })
    }

    pub fn info(&self) -> &SdkInfo {
        &self.info
    }

    pub fn objects<'a>(&'a self) -> Result<ObjectsIter> {
        Ok(ObjectsIter {
            source: ObjectIterSource::from_path(&self.path)?,
        })
    }
}
<|endoftext|>


<commit_before>
fn generate_table () {

    let pi: f64 = 3.1415926536897932384626;
    let k1: f64 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    //let num_elms: uint = num_bits;
    let mul: uint = 1<<(num_bits-2);

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("mul {}", mul);
    println!("1<<(num_bits-2) {}", ((1i << (num_bits-2)) as f64));
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    println!("let cordic_tab = [");

    let shift: f64 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f64 = 1f64/shift.powi(ii as i32);
        let cur: f64 = ipow.atan() * (mul as f64);

        if ii % 4 == 0 && ii > 0 {
            println!("");
        }
        if ii == 0 {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        } else {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        }
    }

    println!("];");
}

fn int_to_f64 (lhs: int) -> f64 {
    let rhs: f64 = unsafe {
        std::mem::transmute(lhs)
    };
    return rhs;
}

fn f64_to_int (lhs: f64) -> int {
    let rhs: int = unsafe {
        std::mem::transmute(lhs)
    };
    return rhs;
}

fn sin(theta: f64) {

    let num_bits: uint = 32;

    let k1: f64 = 0.6072529350088812561694; // 1/k
    let mul: int = 1<<(num_bits-2);
    let cordic_k1: f64 = k1 * (mul as f64);
    //println!("k1 - {}, mul - {}, cordic_k1 - {:X}", k1, mul, cordic_k1);

    let mut x: int = cordic_k1.floor() as int; //0x26DD3B6A;
    let mut y: int = 0;
    let mut z: int = theta.floor() as int;
    let mut tx: int;
    let mut ty: int ;
    let mut tz: int;

    let mut d: int;
    let cordic_tab = [
        0x3243f6a8, 0x1dac6705, 0xfadbafc, 0x7f56ea6,
        0x3feab76, 0x1ffd55b, 0xfffaaa, 0x7fff55,
        0x3fffea, 0x1ffffd, 0xfffff, 0x7ffff,
        0x3ffff, 0x1ffff, 0xffff, 0x7fff,
        0x3fff, 0x1fff, 0xfff, 0x7ff,
        0x3ff, 0x1ff, 0xff, 0x7f,
        0x3f, 0x1f, 0xf, 0x8,
        0x4, 0x2, 0x1, 0x0, ];

    for k in range(0, num_bits) {
        if z >= 0 {
            d = 0;
        } else {
            d = -1;
        }

        println!("z {}", z);

        tx = x - (((y>>k) ^ d) - d);
        ty = y + (((x>>k) ^ d) - d);
        tz = z - ((cordic_tab[k] ^ d) - d);
        println!("{} {} {} {} {} {}", k, x, y, tx, ty, tz);
        x = tx; y = ty; z = tz;
    }
}

fn main() {
    let i: int = 42882;
    let f: f64 = 3498043.4824;
    assert!(int_to_f64(f64_to_int(f)) == f);
    assert!(f64_to_int(int_to_f64(i)) == i);

    generate_table();

    let theta: f64 = 33732594.261305;
    sin(theta);
}
<commit_msg>prints a table of sin values - Fixes #1<commit_after>
fn generate_table () {

    let pi: f64 = 3.1415926536897932384626;
    let k1: f64 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    //let num_elms: uint = num_bits;
    let mul: uint = 1<<(num_bits-2);

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("mul {}", mul);
    println!("1<<(num_bits-2) {}", ((1i << (num_bits-2)) as f64));
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    println!("let cordic_tab = [");

    let shift: f64 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f64 = 1f64/shift.powi(ii as i32);
        let cur: f64 = ipow.atan() * (mul as f64);

        if ii % 4 == 0 && ii > 0 {
            println!("");
        }
        if ii == 0 {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        } else {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        }
    }

    println!("];");
}

fn int_to_f64 (lhs: int) -> f64 {
    let rhs: f64 = unsafe {
        std::mem::transmute(lhs)
    };
    return rhs;
}

fn f64_to_int (lhs: f64) -> int {
    let rhs: int = unsafe {
        std::mem::transmute(lhs)
    };
    return rhs;
}

fn sin(theta: f64) -> f64 {

    let num_bits: uint = 32;

    let k1: f64 = 0.6072529350088812561694; // 1/k
    let muli: int = 1<<(num_bits-2);
    let mul: f64 = muli as f64;

    let cordic_k1: f64 = k1 * mul;
    //println!("k1 - {}, mul - {}, cordic_k1 - {:X}", k1, mul, cordic_k1);

    let mut x: int = cordic_k1.floor() as int; //0x26DD3B6A;
    let mut y: int = 0;
    let mut z: int = (mul * theta).floor() as int;
    let mut tx: int;
    let mut ty: int;
    let mut tz: int;

    //println!("z {}", z);

    let mut d: int;
    let cordic_tab = [
        0x3243f6a8, 0x1dac6705, 0xfadbafc, 0x7f56ea6,
        0x3feab76, 0x1ffd55b, 0xfffaaa, 0x7fff55,
        0x3fffea, 0x1ffffd, 0xfffff, 0x7ffff,
        0x3ffff, 0x1ffff, 0xffff, 0x7fff,
        0x3fff, 0x1fff, 0xfff, 0x7ff,
        0x3ff, 0x1ff, 0xff, 0x7f,
        0x3f, 0x1f, 0xf, 0x8,
        0x4, 0x2, 0x1, 0x0, ];

    for k in range(0, num_bits) {
        if z >= 0 {
            d = 0;
        } else {
            d = -1;
        }

        //println!("z {}", z);

        tx = x - (((y>>k) ^ d) - d);
        ty = y + (((x>>k) ^ d) - d);
        tz = z - ((cordic_tab[k] ^ d) - d);
        //println!("{} {} {} {} {} {}", k, x, y, tx, ty, tz);
        x = tx; y = ty; z = tz;
    }

    let s: f64 = (y as f64)/(mul as f64);

    return s;

}

fn main() {
    let i: int = 42882;
    let f: f64 = 3498043.4824;
    assert!(int_to_f64(f64_to_int(f)) == f);
    assert!(f64_to_int(int_to_f64(i)) == i);

    generate_table();

    //let theta: f64 = 33732594.261305;

    let frac_pi_2: f64 = 3.1415926536897932384626/2.0;

    for ii in range(0i, 50) {

        let cur: f64 = ii as f64;

        let theta: f64 = cur/50.0 * frac_pi_2;
        let s: f64 = sin(theta);

            println!("s {}", s);
    }

}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::ast;
use syntax::codemap::{self, CodeMap, Span, BytePos};
use syntax::visit;

use strings::string_buffer::StringBuffer;

use Indent;
use utils;
use config::Config;
use rewrite::{Rewrite, RewriteContext};
use comment::rewrite_comment;
use macros::rewrite_macro;

pub struct FmtVisitor<'a> {
    pub codemap: &'a CodeMap,
    pub buffer: StringBuffer,
    pub last_pos: BytePos,
    // TODO: RAII util for indenting
    pub block_indent: Indent,
    pub config: &'a Config,
}

impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
    // FIXME: We'd rather not format expressions here, as we have little
    // context. How are we still reaching this?
    fn visit_expr(&mut self, ex: &'v ast::Expr) {
        debug!("visit_expr: {:?} {:?}",
               self.codemap.lookup_char_pos(ex.span.lo),
               self.codemap.lookup_char_pos(ex.span.hi));
        self.format_missing(ex.span.lo);

        let offset = self.buffer.cur_offset();
        // FIXME: We put the entire offset into the block_indent, which might not be correct in all
        // situations.
        let rewrite = ex.rewrite(&self.get_context(),
                                 self.config.max_width - offset,
                                 Indent::new(offset, 0));

        if let Some(new_str) = rewrite {
            self.buffer.push_str(&new_str);
            self.last_pos = ex.span.hi;
        }
    }

    fn visit_stmt(&mut self, stmt: &'v ast::Stmt) {
        match stmt.node {
            ast::Stmt_::StmtDecl(ref decl, _) => {
                match decl.node {
                    ast::Decl_::DeclLocal(ref local) => self.visit_let(local, stmt.span),
                    ast::Decl_::DeclItem(..) => visit::walk_stmt(self, stmt),
                }
            }
            ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
                self.format_missing_with_indent(stmt.span.lo, self.config);
                let suffix = if let ast::Stmt_::StmtExpr(..) = stmt.node {
                    ""
                } else {
                    ";"
                };

                // 1 = trailing semicolon;
                let rewrite = ex.rewrite(&self.get_context(),
                                         self.config.max_width - self.block_indent.width() -
                                         suffix.len(),
                                         self.block_indent);

                if let Some(new_str) = rewrite {
                    self.buffer.push_str(&new_str);
                    self.buffer.push_str(suffix);
                    self.last_pos = stmt.span.hi;
                }
            }
            ast::Stmt_::StmtMac(ref _mac, _macro_style) => {
                self.format_missing_with_indent(stmt.span.lo, self.config);
                visit::walk_stmt(self, stmt);
            }
        }
    }

    fn visit_block(&mut self, b: &'v ast::Block) {
        debug!("visit_block: {:?} {:?}",
               self.codemap.lookup_char_pos(b.span.lo),
               self.codemap.lookup_char_pos(b.span.hi));

        // Check if this block has braces.
        let snippet = self.snippet(b.span);
        let has_braces = &snippet[..1] == "{" || &snippet[..6] == "unsafe";
        let brace_compensation = if has_braces {
            BytePos(1)
        } else {
            BytePos(0)
        };

        self.last_pos = self.last_pos + brace_compensation;
        self.block_indent = self.block_indent.block_indent(self.config);
        self.buffer.push_str("{");

        for stmt in &b.stmts {
            self.visit_stmt(&stmt)
        }

        match b.expr {
            Some(ref e) => {
                self.format_missing_with_indent(e.span.lo, self.config);
                self.visit_expr(e);
            }
            None => {}
        }

        self.block_indent = self.block_indent.block_unindent(self.config);
        // TODO: we should compress any newlines here to just one
        self.format_missing_with_indent(b.span.hi - brace_compensation, self.config);
        self.buffer.push_str("}");
        self.last_pos = b.span.hi;
    }

    // Note that this only gets called for function definitions. Required methods
    // on traits do not get handled here.
    fn visit_fn(&mut self,
                fk: visit::FnKind<'v>,
                fd: &'v ast::FnDecl,
                b: &'v ast::Block,
                s: Span,
                _: ast::NodeId) {

        let indent = self.block_indent;
        let rewrite = match fk {
            visit::FnKind::ItemFn(ident,
                                  ref generics,
                                  ref unsafety,
                                  ref constness,
                                  ref abi,
                                  vis) => {
                self.rewrite_fn(indent,
                                ident,
                                fd,
                                None,
                                generics,
                                unsafety,
                                constness,
                                abi,
                                vis,
                                codemap::mk_sp(s.lo, b.span.lo))
            }
            visit::FnKind::Method(ident, ref sig, vis) => {
                self.rewrite_fn(indent,
                                ident,
                                fd,
                                Some(&sig.explicit_self),
                                &sig.generics,
                                &sig.unsafety,
                                &sig.constness,
                                &sig.abi,
                                vis.unwrap_or(ast::Visibility::Inherited),
                                codemap::mk_sp(s.lo, b.span.lo))
            }
            visit::FnKind::Closure => None,
        };

        if let Some(fn_str) = rewrite {
            self.format_missing_with_indent(s.lo, self.config);
            self.buffer.push_str(&fn_str);
        } else {
            self.format_missing(b.span.lo);
        }

        self.last_pos = b.span.lo;
        self.visit_block(b)
    }

    fn visit_item(&mut self, item: &'v ast::Item) {
        // Don't look at attributes for modules.
        // We want to avoid looking at attributes in another file, which the AST
        // doesn't distinguish. FIXME This is overly conservative and means we miss
        // attributes on inline modules.
        match item.node {
            ast::Item_::ItemMod(_) => {}
            _ => {
                if self.visit_attrs(&item.attrs) {
                    return;
                }
            }
        }

        match item.node {
            ast::Item_::ItemUse(ref vp) => {
                self.format_import(item.vis, vp, item.span);
            }
            ast::Item_::ItemImpl(..) |
            ast::Item_::ItemTrait(..) => {
                self.block_indent = self.block_indent.block_indent(self.config);
                visit::walk_item(self, item);
                self.block_indent = self.block_indent.block_unindent(self.config);
            }
            ast::Item_::ItemExternCrate(_) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                let new_str = self.snippet(item.span);
                self.buffer.push_str(&new_str);
                self.last_pos = item.span.hi;
            }
            ast::Item_::ItemStruct(ref def, ref generics) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                self.visit_struct(item.ident, item.vis, def, generics, item.span);
            }
            ast::Item_::ItemEnum(ref def, ref generics) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                self.visit_enum(item.ident, item.vis, def, generics, item.span);
                self.last_pos = item.span.hi;
            }
            ast::Item_::ItemMod(ref module) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                self.format_mod(module, item.span, item.ident);
            }
            ast::Item_::ItemMac(..) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                // TODO: we cannot format these yet, because of a bad span.
                // See rust lang issue #28424.
                // visit::walk_item(self, item);
            }
            _ => {
                visit::walk_item(self, item);
            }
        }
    }

    fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
        if self.visit_attrs(&ti.attrs) {
            return;
        }

        if let ast::TraitItem_::MethodTraitItem(ref sig, None) = ti.node {
            self.format_missing_with_indent(ti.span.lo, self.config);

            let indent = self.block_indent;
            let new_fn = self.rewrite_required_fn(indent, ti.ident, sig, ti.span);

            if let Some(fn_str) = new_fn {
                self.buffer.push_str(&fn_str);
                self.last_pos = ti.span.hi;
            }
        }
        // TODO: format trait types.

        visit::walk_trait_item(self, ti)
    }

    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
        if self.visit_attrs(&ii.attrs) {
            return;
        }
        visit::walk_impl_item(self, ii)
    }

    fn visit_mac(&mut self, mac: &'v ast::Mac) {
        // 1 = ;
        let width = self.config.max_width - self.block_indent.width() - 1;
        let rewrite = rewrite_macro(mac, &self.get_context(), width, self.block_indent);

        if let Some(res) = rewrite {
            self.buffer.push_str(&res);
            self.last_pos = mac.span.hi;
        }
    }
}

impl<'a> FmtVisitor<'a> {
    pub fn from_codemap<'b>(codemap: &'b CodeMap, config: &'b Config) -> FmtVisitor<'b> {
        FmtVisitor {
            codemap: codemap,
            buffer: StringBuffer::new(),
            last_pos: BytePos(0),
            block_indent: Indent { block_indent: 0, alignment: 0 },
            config: config,
        }
    }

    pub fn snippet(&self, span: Span) -> String {
        match self.codemap.span_to_snippet(span) {
            Ok(s) => s,
            Err(_) => {
                println!("Couldn't make snippet for span {:?}->{:?}",
                         self.codemap.lookup_char_pos(span.lo),
                         self.codemap.lookup_char_pos(span.hi));
                "".to_owned()
            }
        }
    }

    // Returns true if we should skip the following item.
    pub fn visit_attrs(&mut self, attrs: &[ast::Attribute]) -> bool {
        if attrs.is_empty() {
            return false;
        }

        let first = &attrs[0];
        self.format_missing_with_indent(first.span.lo, self.config);

        if utils::contains_skip(attrs) {
            true
        } else {
            let rewrite = attrs.rewrite(&self.get_context(),
                                        self.config.max_width - self.block_indent.width(),
                                        self.block_indent)
                               .unwrap();
            self.buffer.push_str(&rewrite);
            let last = attrs.last().unwrap();
            self.last_pos = last.span.hi;
            false
        }
    }

    fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident) {
        debug!("FmtVisitor::format_mod: ident: {:?}, span: {:?}", ident, s);

        // Decide whether this is an inline mod or an external mod.
        let local_file_name = self.codemap.span_to_filename(s);
        let is_internal = local_file_name == self.codemap.span_to_filename(m.inner);

        // TODO: Should rewrite properly `mod X;`

        if is_internal {
            debug!("FmtVisitor::format_mod: internal mod");
            self.block_indent = self.block_indent.block_indent(self.config);
            visit::walk_mod(self, m);
            debug!("... last_pos after: {:?}", self.last_pos);
            self.block_indent = self.block_indent.block_unindent(self.config);
        }
    }

    pub fn format_separate_mod(&mut self, m: &ast::Mod, filename: &str) {
        let filemap = self.codemap.get_filemap(filename);
        self.last_pos = filemap.start_pos;
        self.block_indent = Indent::empty();
        visit::walk_mod(self, m);
        self.format_missing(filemap.end_pos);
    }

    fn format_import(&mut self, vis: ast::Visibility, vp: &ast::ViewPath, span: Span) {
        let vis = utils::format_visibility(vis);
        let mut offset = self.block_indent;
        offset.alignment += vis.len() + "use ".len();
        let context = RewriteContext {
            codemap: self.codemap,
            config: self.config,
            block_indent: self.block_indent,
            overflow_indent: Indent::empty(),
        };
        // 1 = ";"
        match vp.rewrite(&context, self.config.max_width - offset.width() - 1, offset) {
            Some(ref s) if s.is_empty() => {
                // Format up to last newline
                let prev_span = codemap::mk_sp(self.last_pos, span.lo);
                let span_end = match self.snippet(prev_span).rfind('\n') {
                    Some(offset) => self.last_pos + BytePos(offset as u32),
                    None => span.lo,
                };
                self.format_missing(span_end);
                self.last_pos = span.hi;
            }
            Some(ref s) => {
                let s = format!("{}use {};", vis, s);
                self.format_missing_with_indent(span.lo, self.config);
                self.buffer.push_str(&s);
                self.last_pos = span.hi;
            }
            None => {
                self.format_missing_with_indent(span.lo, self.config);
                self.format_missing(span.hi);
            }
        }
    }

    pub fn get_context(&self) -> RewriteContext {
        RewriteContext {
            codemap: self.codemap,
            config: self.config,
            block_indent: self.block_indent,
            overflow_indent: Indent::empty(),
        }
    }
}

impl<'a> Rewrite for [ast::Attribute] {
    fn rewrite(&self, context: &RewriteContext, _: usize, offset: Indent) -> Option<String> {
        let mut result = String::new();
        if self.is_empty() {
            return Some(result);
        }
        let indent = offset.to_string(context.config);

        for (i, a) in self.iter().enumerate() {
            let a_str = context.snippet(a.span);

            if i > 0 {
                let comment = context.snippet(codemap::mk_sp(self[i-1].span.hi, a.span.lo));
                // This particular horror show is to preserve line breaks in between doc
                // comments. An alternative would be to force such line breaks to start
                // with the usual doc comment token.
                let multi_line = a_str.starts_with("//") && comment.matches('\n').count() > 1;
                let comment = comment.trim();
                if !comment.is_empty() {
                    let comment = rewrite_comment(comment,
                                                  false,
                                                  context.config.max_width - offset.width(),
                                                  offset,
                                                  context.config);
                    result.push_str(&indent);
                    result.push_str(&comment);
                    result.push('\n');
                } else if multi_line {
                    result.push('\n');
                }
                result.push_str(&indent);
            }

            result.push_str(&a_str);

            if i < self.len() - 1 {
                result.push('\n');
            }
        }

        Some(result)
    }
}
<commit_msg>Use the block_indent inside visit_expr.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax::ast;
use syntax::codemap::{self, CodeMap, Span, BytePos};
use syntax::visit;

use strings::string_buffer::StringBuffer;

use Indent;
use utils;
use config::Config;
use rewrite::{Rewrite, RewriteContext};
use comment::rewrite_comment;
use macros::rewrite_macro;

pub struct FmtVisitor<'a> {
    pub codemap: &'a CodeMap,
    pub buffer: StringBuffer,
    pub last_pos: BytePos,
    // TODO: RAII util for indenting
    pub block_indent: Indent,
    pub config: &'a Config,
}

impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
    // FIXME: We'd rather not format expressions here, as we have little
    // context. How are we still reaching this?
    fn visit_expr(&mut self, ex: &'v ast::Expr) {
        debug!("visit_expr: {:?} {:?}",
               self.codemap.lookup_char_pos(ex.span.lo),
               self.codemap.lookup_char_pos(ex.span.hi));
        self.format_missing(ex.span.lo);

        let rewrite = ex.rewrite(&self.get_context(),
                                 self.config.max_width - self.block_indent.width(),
                                 self.block_indent);

        if let Some(new_str) = rewrite {
            self.buffer.push_str(&new_str);
            self.last_pos = ex.span.hi;
        }
    }

    fn visit_stmt(&mut self, stmt: &'v ast::Stmt) {
        match stmt.node {
            ast::Stmt_::StmtDecl(ref decl, _) => {
                match decl.node {
                    ast::Decl_::DeclLocal(ref local) => self.visit_let(local, stmt.span),
                    ast::Decl_::DeclItem(..) => visit::walk_stmt(self, stmt),
                }
            }
            ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
                self.format_missing_with_indent(stmt.span.lo, self.config);
                let suffix = if let ast::Stmt_::StmtExpr(..) = stmt.node {
                    ""
                } else {
                    ";"
                };

                // 1 = trailing semicolon;
                let rewrite = ex.rewrite(&self.get_context(),
                                         self.config.max_width - self.block_indent.width() -
                                         suffix.len(),
                                         self.block_indent);

                if let Some(new_str) = rewrite {
                    self.buffer.push_str(&new_str);
                    self.buffer.push_str(suffix);
                    self.last_pos = stmt.span.hi;
                }
            }
            ast::Stmt_::StmtMac(ref _mac, _macro_style) => {
                self.format_missing_with_indent(stmt.span.lo, self.config);
                visit::walk_stmt(self, stmt);
            }
        }
    }

    fn visit_block(&mut self, b: &'v ast::Block) {
        debug!("visit_block: {:?} {:?}",
               self.codemap.lookup_char_pos(b.span.lo),
               self.codemap.lookup_char_pos(b.span.hi));

        // Check if this block has braces.
        let snippet = self.snippet(b.span);
        let has_braces = &snippet[..1] == "{" || &snippet[..6] == "unsafe";
        let brace_compensation = if has_braces {
            BytePos(1)
        } else {
            BytePos(0)
        };

        self.last_pos = self.last_pos + brace_compensation;
        self.block_indent = self.block_indent.block_indent(self.config);
        self.buffer.push_str("{");

        for stmt in &b.stmts {
            self.visit_stmt(&stmt)
        }

        match b.expr {
            Some(ref e) => {
                self.format_missing_with_indent(e.span.lo, self.config);
                self.visit_expr(e);
            }
            None => {}
        }

        self.block_indent = self.block_indent.block_unindent(self.config);
        // TODO: we should compress any newlines here to just one
        self.format_missing_with_indent(b.span.hi - brace_compensation, self.config);
        self.buffer.push_str("}");
        self.last_pos = b.span.hi;
    }

    // Note that this only gets called for function definitions. Required methods
    // on traits do not get handled here.
    fn visit_fn(&mut self,
                fk: visit::FnKind<'v>,
                fd: &'v ast::FnDecl,
                b: &'v ast::Block,
                s: Span,
                _: ast::NodeId) {

        let indent = self.block_indent;
        let rewrite = match fk {
            visit::FnKind::ItemFn(ident,
                                  ref generics,
                                  ref unsafety,
                                  ref constness,
                                  ref abi,
                                  vis) => {
                self.rewrite_fn(indent,
                                ident,
                                fd,
                                None,
                                generics,
                                unsafety,
                                constness,
                                abi,
                                vis,
                                codemap::mk_sp(s.lo, b.span.lo))
            }
            visit::FnKind::Method(ident, ref sig, vis) => {
                self.rewrite_fn(indent,
                                ident,
                                fd,
                                Some(&sig.explicit_self),
                                &sig.generics,
                                &sig.unsafety,
                                &sig.constness,
                                &sig.abi,
                                vis.unwrap_or(ast::Visibility::Inherited),
                                codemap::mk_sp(s.lo, b.span.lo))
            }
            visit::FnKind::Closure => None,
        };

        if let Some(fn_str) = rewrite {
            self.format_missing_with_indent(s.lo, self.config);
            self.buffer.push_str(&fn_str);
        } else {
            self.format_missing(b.span.lo);
        }

        self.last_pos = b.span.lo;
        self.visit_block(b)
    }

    fn visit_item(&mut self, item: &'v ast::Item) {
        // Don't look at attributes for modules.
        // We want to avoid looking at attributes in another file, which the AST
        // doesn't distinguish. FIXME This is overly conservative and means we miss
        // attributes on inline modules.
        match item.node {
            ast::Item_::ItemMod(_) => {}
            _ => {
                if self.visit_attrs(&item.attrs) {
                    return;
                }
            }
        }

        match item.node {
            ast::Item_::ItemUse(ref vp) => {
                self.format_import(item.vis, vp, item.span);
            }
            ast::Item_::ItemImpl(..) |
            ast::Item_::ItemTrait(..) => {
                self.block_indent = self.block_indent.block_indent(self.config);
                visit::walk_item(self, item);
                self.block_indent = self.block_indent.block_unindent(self.config);
            }
            ast::Item_::ItemExternCrate(_) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                let new_str = self.snippet(item.span);
                self.buffer.push_str(&new_str);
                self.last_pos = item.span.hi;
            }
            ast::Item_::ItemStruct(ref def, ref generics) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                self.visit_struct(item.ident, item.vis, def, generics, item.span);
            }
            ast::Item_::ItemEnum(ref def, ref generics) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                self.visit_enum(item.ident, item.vis, def, generics, item.span);
                self.last_pos = item.span.hi;
            }
            ast::Item_::ItemMod(ref module) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                self.format_mod(module, item.span, item.ident);
            }
            ast::Item_::ItemMac(..) => {
                self.format_missing_with_indent(item.span.lo, self.config);
                // TODO: we cannot format these yet, because of a bad span.
                // See rust lang issue #28424.
                // visit::walk_item(self, item);
            }
            _ => {
                visit::walk_item(self, item);
            }
        }
    }

    fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
        if self.visit_attrs(&ti.attrs) {
            return;
        }

        if let ast::TraitItem_::MethodTraitItem(ref sig, None) = ti.node {
            self.format_missing_with_indent(ti.span.lo, self.config);

            let indent = self.block_indent;
            let new_fn = self.rewrite_required_fn(indent, ti.ident, sig, ti.span);

            if let Some(fn_str) = new_fn {
                self.buffer.push_str(&fn_str);
                self.last_pos = ti.span.hi;
            }
        }
        // TODO: format trait types.

        visit::walk_trait_item(self, ti)
    }

    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
        if self.visit_attrs(&ii.attrs) {
            return;
        }
        visit::walk_impl_item(self, ii)
    }

    fn visit_mac(&mut self, mac: &'v ast::Mac) {
        // 1 = ;
        let width = self.config.max_width - self.block_indent.width() - 1;
        let rewrite = rewrite_macro(mac, &self.get_context(), width, self.block_indent);

        if let Some(res) = rewrite {
            self.buffer.push_str(&res);
            self.last_pos = mac.span.hi;
        }
    }
}

impl<'a> FmtVisitor<'a> {
    pub fn from_codemap<'b>(codemap: &'b CodeMap, config: &'b Config) -> FmtVisitor<'b> {
        FmtVisitor {
            codemap: codemap,
            buffer: StringBuffer::new(),
            last_pos: BytePos(0),
            block_indent: Indent { block_indent: 0, alignment: 0 },
            config: config,
        }
    }

    pub fn snippet(&self, span: Span) -> String {
        match self.codemap.span_to_snippet(span) {
            Ok(s) => s,
            Err(_) => {
                println!("Couldn't make snippet for span {:?}->{:?}",
                         self.codemap.lookup_char_pos(span.lo),
                         self.codemap.lookup_char_pos(span.hi));
                "".to_owned()
            }
        }
    }

    // Returns true if we should skip the following item.
    pub fn visit_attrs(&mut self, attrs: &[ast::Attribute]) -> bool {
        if attrs.is_empty() {
            return false;
        }

        let first = &attrs[0];
        self.format_missing_with_indent(first.span.lo, self.config);

        if utils::contains_skip(attrs) {
            true
        } else {
            let rewrite = attrs.rewrite(&self.get_context(),
                                        self.config.max_width - self.block_indent.width(),
                                        self.block_indent)
                               .unwrap();
            self.buffer.push_str(&rewrite);
            let last = attrs.last().unwrap();
            self.last_pos = last.span.hi;
            false
        }
    }

    fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident) {
        debug!("FmtVisitor::format_mod: ident: {:?}, span: {:?}", ident, s);

        // Decide whether this is an inline mod or an external mod.
        let local_file_name = self.codemap.span_to_filename(s);
        let is_internal = local_file_name == self.codemap.span_to_filename(m.inner);

        // TODO: Should rewrite properly `mod X;`

        if is_internal {
            debug!("FmtVisitor::format_mod: internal mod");
            self.block_indent = self.block_indent.block_indent(self.config);
            visit::walk_mod(self, m);
            debug!("... last_pos after: {:?}", self.last_pos);
            self.block_indent = self.block_indent.block_unindent(self.config);
        }
    }

    pub fn format_separate_mod(&mut self, m: &ast::Mod, filename: &str) {
        let filemap = self.codemap.get_filemap(filename);
        self.last_pos = filemap.start_pos;
        self.block_indent = Indent::empty();
        visit::walk_mod(self, m);
        self.format_missing(filemap.end_pos);
    }

    fn format_import(&mut self, vis: ast::Visibility, vp: &ast::ViewPath, span: Span) {
        let vis = utils::format_visibility(vis);
        let mut offset = self.block_indent;
        offset.alignment += vis.len() + "use ".len();
        let context = RewriteContext {
            codemap: self.codemap,
            config: self.config,
            block_indent: self.block_indent,
            overflow_indent: Indent::empty(),
        };
        // 1 = ";"
        match vp.rewrite(&context, self.config.max_width - offset.width() - 1, offset) {
            Some(ref s) if s.is_empty() => {
                // Format up to last newline
                let prev_span = codemap::mk_sp(self.last_pos, span.lo);
                let span_end = match self.snippet(prev_span).rfind('\n') {
                    Some(offset) => self.last_pos + BytePos(offset as u32),
                    None => span.lo,
                };
                self.format_missing(span_end);
                self.last_pos = span.hi;
            }
            Some(ref s) => {
                let s = format!("{}use {};", vis, s);
                self.format_missing_with_indent(span.lo, self.config);
                self.buffer.push_str(&s);
                self.last_pos = span.hi;
            }
            None => {
                self.format_missing_with_indent(span.lo, self.config);
                self.format_missing(span.hi);
            }
        }
    }

    pub fn get_context(&self) -> RewriteContext {
        RewriteContext {
            codemap: self.codemap,
            config: self.config,
            block_indent: self.block_indent,
            overflow_indent: Indent::empty(),
        }
    }
}

impl<'a> Rewrite for [ast::Attribute] {
    fn rewrite(&self, context: &RewriteContext, _: usize, offset: Indent) -> Option<String> {
        let mut result = String::new();
        if self.is_empty() {
            return Some(result);
        }
        let indent = offset.to_string(context.config);

        for (i, a) in self.iter().enumerate() {
            let a_str = context.snippet(a.span);

            if i > 0 {
                let comment = context.snippet(codemap::mk_sp(self[i-1].span.hi, a.span.lo));
                // This particular horror show is to preserve line breaks in between doc
                // comments. An alternative would be to force such line breaks to start
                // with the usual doc comment token.
                let multi_line = a_str.starts_with("//") && comment.matches('\n').count() > 1;
                let comment = comment.trim();
                if !comment.is_empty() {
                    let comment = rewrite_comment(comment,
                                                  false,
                                                  context.config.max_width - offset.width(),
                                                  offset,
                                                  context.config);
                    result.push_str(&indent);
                    result.push_str(&comment);
                    result.push('\n');
                } else if multi_line {
                    result.push('\n');
                }
                result.push_str(&indent);
            }

            result.push_str(&a_str);

            if i < self.len() - 1 {
                result.push('\n');
            }
        }

        Some(result)
    }
}
<|endoftext|>


<commit_before><commit_msg>Added first model implementation<commit_after>use super::schema::posts;
use rocket::{Request, Data};
use rocket::data::{self, FromData};
use rocket::http::Status;
use rocket::Outcome::*;
use serde_json;

#[derive(Queryable)]
#[derive(Serialize, Deserialize)]
pub struct Post {
    pub id: i32,
    pub title: String,
    pub body: String,
    pub pinned: bool,
}

// This enables using PostData from incoming request data
pub struct PostData {
    pub title: String,
    pub body: String,
    pub pinned: bool,
}

impl FromData for PostData {
    type Error = String;
    #[allow(unused_variables)]
    fn from_data(req: &Request, data: Data) -> data::Outcome<Self,String>{
       let reader = data.open();
       match serve_json::from_reader(reader).map(|val| val) {
            Ok(value) => Success(value),
            Err(e) => Failure((Status::BadRequest, e.to_string())),
       }
    }
}

<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
use collections::HashMap;
use std::io::{Open, Read, Write, TempDir};
use std::num::Zero;
use std::comm::{Data, Empty, Disconnected};
use sync::{Arc, RWLock};
use sync::Future;
use rand::task_rng;
use rand::distributions::{IndependentSample, Range};
use rand::distributions::range::SampleRange;
use native::io::file;
use native::io::file::FileDesc;
use std::rt::rtio::RtioFileStream;

static PAGE_SIZE: uint = 4 * 1024;
/* how much of the page_id should be reserved for pages */
static PAGE_BITS: uint = 4;

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	path: Path,
}

struct BufferEntry {
	frame: Arc<RWLock<BufferFrame>>,
}

#[deriving(Eq)]
enum Status {
	Free,
	Fixed(uint),
}

struct BufferFrame {
	page_id: u64,
	data: Vec<u8>,
	fixed: Status,
}

/* Destructor trait implementation */
impl Drop for BufferManager {
	fn drop(&mut self) {
		// TODO
		info!("Dropping");
	}
}

impl BufferManager {
	pub fn new(size: uint, path: Path) -> BufferManager {
		let h = HashMap::with_capacity(size);
		BufferManager {size: size, entries: h, path: path}
	}

	fn open_or_create(&self, page_id: u64) -> FileDesc {
		let (segment, _) = split_segment(page_id);
		let file_path = self.path.join(segment.to_str());
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => return f,
			Err(_) => self.create(page_id),
		};
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => f,
			Err(e) => fail!("Failed reopening written file: {}", e),
		}
	}

	fn create(&self, page_id: u64) {
		let (segment, offset) = split_segment(page_id);
		let path = self.path.join(segment.to_str());

		match file::open(&path.to_c_str(), Open, Write) {
			Ok(mut f) => {
				match f.pwrite([0_u8, ..PAGE_SIZE], offset * PAGE_SIZE as u64) {
					Ok(_) => (),
					//Err(e) => fail!("Failed pwriting to file {}: {}", &path.to_c_str().as_str(), e),
					// in this case, err means everything is fine, since there is a bug in Rust' libnative
					Err(_) => (),
				};
			},
			Err(e) => fail!("Failed opening file for write: {}", e),
		};
	}

	/*
	 * returns true if page could be loaded
	 */
	fn load_page(&mut self, page_id: u64) -> bool {
		if self.entries.len() == self.size {
			if !self.evict_page() {
				return false;
			}
		}
		let (_, offset) = split_segment(page_id);

		let mut file_handle = self.open_or_create(page_id);
		let mut buf = [0_u8, ..PAGE_SIZE];
		let content = match file_handle.pread(buf, offset * PAGE_SIZE as u64) {
			Ok(_) => {
				Vec::from_slice(buf)
				/*
				if n == PAGE_SIZE as int {
					Vec::from_slice(buf)
				} else {
					fail!("pread failed: wanted {}, got {}",
						PAGE_SIZE, n)
				}*/
			},
			Err(e) => fail!("Couldn't read from page: {}", e),
		};

		let frame = BufferFrame {data: content, page_id: page_id, fixed: Free};
		let entry = BufferEntry {frame: Arc::new(RWLock::new(frame))};
		self.entries.insert(page_id, entry);
		true
	}

	/*
	 * return false if no page could be evicted
	 */
	fn evict_page(&mut self) -> bool {
		let random_key = {
			let mut free_keys = self.entries.iter().filter_map(|e| {
				// iterate over entries, check if they are free
				// and return the keys of the free entries
				let (k,v) = e;
				let frame = v.frame.read();
				if frame.fixed == Free {
					Some(k)
				} else {
					None
				}
			});
			// pick a random key
			sample(&mut free_keys).map(|v| v.clone())
		};

		match random_key {
			None => false,
			Some(key) => self.entries.remove(&key),
		}
	}

	pub fn fix_page(&mut self, page_id: u64) -> Option<Arc<RWLock<BufferFrame>>> {
		if !self.entries.contains_key(&page_id) {
			if !self.load_page(page_id) {
				return None;
			}
		}
		let entry = self.entries.get(&page_id);
		{
			let mut f = entry.frame.write();
			f.fixed = match f.fixed {
				Free => Fixed(1),
				Fixed(n) => Fixed(n+1),
			};
		}
		// Arcs can be cloned and they will all point to the same RWLock
		Some(entry.frame.clone())
	}

	pub fn unfix_page(&mut self, frame: Arc<RWLock<BufferFrame>>, is_dirty: bool) {
		{
			let mut frame = frame.write();
			frame.fixed = match frame.fixed {
				Fixed(1) => Free,
				Fixed(n) => Fixed(n-1),
				Free => fail!("Unfixing unfixed page"),
			};
		}

		if !is_dirty {
			return;
		}
		let frame = frame.read();
		if frame.fixed == Free {
			//info!("writing back page \\#{}", frame.page_id);
			self.write_page(frame.page_id, frame.get_data());
		}
	}

	fn write_page(&mut self, page_id: u64, data: &[u8]) {
		let (segment, offset) = split_segment(page_id);
		let file_path = self.path.join(segment.to_str());
		let mut handle = match file::open(&file_path.to_c_str(), Open, Write) {
			Ok(handle) => handle,
			Err(e) => fail!("Opening file for writing failed: {}", e),
		};

		println!("Writing to segment {}, page {}", segment, offset);
		match handle.pwrite(data, offset * PAGE_SIZE as u64) {
			Ok(_) => (),
			//Err(e) => fail!("Writing to file failed: {}", e),
			// again Rust 0.10 pwrite error
			Err(_) => (),
		};
	}
}

/*
 * A buffer frame, the unit that gets the data
 */
impl BufferFrame {
	/*
	 * get_mut_data returns a borrowed reference to a mutable slice to the vector
	 * contents.
	 */
	pub fn get_mut_data<'a>(&'a mut self) -> &'a mut [u8] {
		self.data.as_mut_slice()
	}
	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

fn sample<'a, T, I:Iterator<T>>(from: &'a mut I) -> Option<T> {
	let from: ~[T] = from.collect();
	let l = from.len();
	if l == 0 {
		return None;
	}
	let index = randrange(l);
	Some(from[index])
}

fn randrange<X: SampleRange + Ord + Zero>(high: X) -> X {
	let between: Range<X> = Range::new(Zero::zero(), high);
	let mut rng = rand::task_rng();
	between.ind_sample(&mut rng)
}

fn split_segment(num: u64) -> (u64, u64) {
	let high = num >> PAGE_BITS;
	let low = num & ((1 << PAGE_BITS) - 1);
	(high, low)
}

#[test]
fn test_create() {
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	let mut bm = BufferManager::new(16, dir.path().clone());
	let pageref = match bm.fix_page(42) {
		Some(p) => p,
		None => fail!("Getting page failed"),
	};
	{
		let mut page = pageref.write();
		let data = page.get_mut_data();
		data[0] = 42;
	}
	bm.unfix_page(pageref, true);
}

#[test]
fn test_threads() {
	use rand::random;
	use std::task::spawn;
	use std::os;

	let pages_in_ram: uint = match os::getenv("PAGES_IN_RAM") {
		Some(v) => from_str(v).expect("PAGES_IN_RAM expects integer"),
		None => 1,
	};
	let pages_on_disk: u64 = match os::getenv("PAGES_ON_DISK") {
		Some(v) => from_str(v).expect("PAGES_ON_DISK expects integer"),
		None => 20,
	};
	let thread_count: uint = match os::getenv("THREADS") {
		Some(v) => from_str(v).expect("THREADS expects integer"),
		None => 3,
	};
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let p = dir.path();
	let p = Path::new(".");

	let mut buffermanager = BufferManager::new(pages_in_ram, p.clone());

	for i in range(0, pages_on_disk) {
		let bf = match buffermanager.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page {}", i),
		};
		{
			let mut lock = bf.write();
			lock.get_mut_data()[0] = 0;
		}
		buffermanager.unfix_page(bf, true);
	}
	let bm = Arc::new(RWLock::new(buffermanager));

	// start scan thread
	let (tx, rx) = channel();
	let bm_scan = bm.clone();
	let mut scan = Future::spawn(proc() {
		let mut counters = Vec::from_elem(pages_on_disk as uint, 0_u8);
		loop {
			info!("Running scan thread...");
			match rx.try_recv() {
				Empty => {
					let page_number = randrange(pages_on_disk);
					let mut bm = bm_scan.write();
					let bf = match bm.fix_page(page_number) {
						Some(frame) => frame,
						None => fail!("Couldn't scan/fix page"),
					};
					let current_val = {
						let lock = bf.read();
						lock.get_data()[0]
					};
					bm.unfix_page(bf, false);
					bm.downgrade();
					// check if the value is going up
					assert!(&current_val >= counters.get(page_number as uint));
					// set to the new value
					let v = counters.get_mut(page_number as uint);
					*v = current_val;

				},
				/*
				 * terminate on both disconnect and when any kind of
				 * data arrives
				 */
				Disconnected => break,
				Data(_) => break,
			};
		}
	});

	// start read/write threads
	let mut rw_threads: Vec<Future<int>> = Vec::new();
	for _ in range(0, thread_count) {
		let bm = bm.clone();
		rw_threads.push(Future::spawn(proc() {
			let is_write = random::<bool>();
			info!("Creating new {} task",
				if is_write {"write"} else {"read"});
			let page_number = randrange(pages_on_disk);
			let mut bm = bm.write();
			if is_write {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				{
					let mut lock = bf.write();
					let data = lock.get_mut_data();
					data[0] = data[0] + 1;
					info!("Wrote to page {}", page_number);
					debug!("data: {}", Vec::from_slice(data));
				}
				bm.unfix_page(bf, is_write);
			} else {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				bm.unfix_page(bf, is_write);
			}
			// return whether we wrote (1) or read (0) as future
			if is_write {1} else {0}
		}));
	}

	// Rust does not have join, but we can wait on Futures which does the same
	let total_count = rw_threads.mut_iter().fold(0, |acc, val| acc + val.get());
	info!("Total count in RAM: {}", total_count);

	// terminate the scan thread and wait until it has completed
	tx.send("terminate");
	scan.get();

	// re-open the pages and check whether all numbers got saved
	let mut bm = BufferManager::new(pages_in_ram, p.clone());
	let mut total_count_on_disk = 0;
	for i in range(0, pages_on_disk) {
		let bf = match bm.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page")
		};
		let value = {
			let lock = bf.read();
			let data = lock.get_data();
			data[0]
		};
		bm.unfix_page(bf, false);
		// cast up from u8 to int
		total_count_on_disk += value as int;
	}
	info!("Total count on disk: {}", total_count_on_disk);
	assert_eq!(total_count, total_count_on_disk);
}
<commit_msg>Added some documentation comments for static params<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
use collections::HashMap;
use std::io::{Open, Read, Write, TempDir};
use std::num::Zero;
use std::comm::{Data, Empty, Disconnected};
use sync::{Arc, RWLock};
use sync::Future;
use rand::task_rng;
use rand::distributions::{IndependentSample, Range};
use rand::distributions::range::SampleRange;
use native::io::file;
use native::io::file::FileDesc;
use std::rt::rtio::RtioFileStream;

/* Linux seems to use 4K segments, that's a good bet */
static PAGE_SIZE: uint = 4 * 1024;
/*
 * how much of the page_id should be reserved for pages?
 * the rest goes for segments. The bigger this is, the larger the segment files are
 * and the more pages they contain. (2^PAGE_BITS)*PAGE_SIZE gives you segment size.
 *
 * Adjust as required.
 */
static PAGE_BITS: uint = 4;

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	path: Path,
}

struct BufferEntry {
	frame: Arc<RWLock<BufferFrame>>,
}

#[deriving(Eq)]
enum Status {
	Free,
	Fixed(uint),
}

struct BufferFrame {
	page_id: u64,
	data: Vec<u8>,
	fixed: Status,
}

/* Destructor trait implementation */
impl Drop for BufferManager {
	fn drop(&mut self) {
		// TODO
		info!("Dropping");
	}
}

impl BufferManager {
	pub fn new(size: uint, path: Path) -> BufferManager {
		let h = HashMap::with_capacity(size);
		BufferManager {size: size, entries: h, path: path}
	}

	fn open_or_create(&self, page_id: u64) -> FileDesc {
		let (segment, _) = split_segment(page_id);
		let file_path = self.path.join(segment.to_str());
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => return f,
			Err(_) => self.create(page_id),
		};
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => f,
			Err(e) => fail!("Failed reopening written file: {}", e),
		}
	}

	fn create(&self, page_id: u64) {
		let (segment, offset) = split_segment(page_id);
		let path = self.path.join(segment.to_str());

		match file::open(&path.to_c_str(), Open, Write) {
			Ok(mut f) => {
				match f.pwrite([0_u8, ..PAGE_SIZE], offset * PAGE_SIZE as u64) {
					Ok(_) => (),
					//Err(e) => fail!("Failed pwriting to file {}: {}", &path.to_c_str().as_str(), e),
					// in this case, err means everything is fine, since there is a bug in Rust' libnative
					Err(_) => (),
				};
			},
			Err(e) => fail!("Failed opening file for write: {}", e),
		};
	}

	/*
	 * returns true if page could be loaded
	 */
	fn load_page(&mut self, page_id: u64) -> bool {
		if self.entries.len() == self.size {
			if !self.evict_page() {
				return false;
			}
		}
		let (_, offset) = split_segment(page_id);

		let mut file_handle = self.open_or_create(page_id);
		let mut buf = [0_u8, ..PAGE_SIZE];
		let content = match file_handle.pread(buf, offset * PAGE_SIZE as u64) {
			Ok(_) => {
				Vec::from_slice(buf)
				/*
				if n == PAGE_SIZE as int {
					Vec::from_slice(buf)
				} else {
					fail!("pread failed: wanted {}, got {}",
						PAGE_SIZE, n)
				}*/
			},
			Err(e) => fail!("Couldn't read from page: {}", e),
		};

		let frame = BufferFrame {data: content, page_id: page_id, fixed: Free};
		let entry = BufferEntry {frame: Arc::new(RWLock::new(frame))};
		self.entries.insert(page_id, entry);
		true
	}

	/*
	 * return false if no page could be evicted
	 */
	fn evict_page(&mut self) -> bool {
		let random_key = {
			let mut free_keys = self.entries.iter().filter_map(|e| {
				// iterate over entries, check if they are free
				// and return the keys of the free entries
				let (k,v) = e;
				let frame = v.frame.read();
				if frame.fixed == Free {
					Some(k)
				} else {
					None
				}
			});
			// pick a random key
			sample(&mut free_keys).map(|v| v.clone())
		};

		match random_key {
			None => false,
			Some(key) => self.entries.remove(&key),
		}
	}

	pub fn fix_page(&mut self, page_id: u64) -> Option<Arc<RWLock<BufferFrame>>> {
		if !self.entries.contains_key(&page_id) {
			if !self.load_page(page_id) {
				return None;
			}
		}
		let entry = self.entries.get(&page_id);
		{
			let mut f = entry.frame.write();
			f.fixed = match f.fixed {
				Free => Fixed(1),
				Fixed(n) => Fixed(n+1),
			};
		}
		// Arcs can be cloned and they will all point to the same RWLock
		Some(entry.frame.clone())
	}

	pub fn unfix_page(&mut self, frame: Arc<RWLock<BufferFrame>>, is_dirty: bool) {
		{
			let mut frame = frame.write();
			frame.fixed = match frame.fixed {
				Fixed(1) => Free,
				Fixed(n) => Fixed(n-1),
				Free => fail!("Unfixing unfixed page"),
			};
		}

		if !is_dirty {
			return;
		}
		let frame = frame.read();
		if frame.fixed == Free {
			//info!("writing back page \\#{}", frame.page_id);
			self.write_page(frame.page_id, frame.get_data());
		}
	}

	fn write_page(&mut self, page_id: u64, data: &[u8]) {
		let (segment, offset) = split_segment(page_id);
		let file_path = self.path.join(segment.to_str());
		let mut handle = match file::open(&file_path.to_c_str(), Open, Write) {
			Ok(handle) => handle,
			Err(e) => fail!("Opening file for writing failed: {}", e),
		};

		info!("Writing to segment {}, offset {}", segment, offset);
		match handle.pwrite(data, offset * PAGE_SIZE as u64) {
			Ok(_) => (),
			//Err(e) => fail!("Writing to file failed: {}", e),
			// again Rust 0.10 pwrite error
			Err(_) => (),
		};
	}
}

/*
 * A buffer frame, the unit that gets the data
 */
impl BufferFrame {
	/*
	 * get_mut_data returns a borrowed reference to a mutable slice to the vector
	 * contents.
	 */
	pub fn get_mut_data<'a>(&'a mut self) -> &'a mut [u8] {
		self.data.as_mut_slice()
	}
	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

fn sample<'a, T, I:Iterator<T>>(from: &'a mut I) -> Option<T> {
	let from: ~[T] = from.collect();
	let l = from.len();
	if l == 0 {
		return None;
	}
	let index = randrange(l);
	Some(from[index])
}

fn randrange<X: SampleRange + Ord + Zero>(high: X) -> X {
	let between: Range<X> = Range::new(Zero::zero(), high);
	let mut rng = rand::task_rng();
	between.ind_sample(&mut rng)
}

fn split_segment(num: u64) -> (u64, u64) {
	let high = num >> PAGE_BITS;
	let low = num & ((1 << PAGE_BITS) - 1);
	(high, low)
}

#[test]
fn test_create() {
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	let mut bm = BufferManager::new(16, dir.path().clone());
	let pageref = match bm.fix_page(42) {
		Some(p) => p,
		None => fail!("Getting page failed"),
	};
	{
		let mut page = pageref.write();
		let data = page.get_mut_data();
		data[0] = 42;
	}
	bm.unfix_page(pageref, true);
}

#[test]
fn test_threads() {
	use rand::random;
	use std::task::spawn;
	use std::os;

	let pages_in_ram: uint = match os::getenv("PAGES_IN_RAM") {
		Some(v) => from_str(v).expect("PAGES_IN_RAM expects integer"),
		None => 1,
	};
	let pages_on_disk: u64 = match os::getenv("PAGES_ON_DISK") {
		Some(v) => from_str(v).expect("PAGES_ON_DISK expects integer"),
		None => 20,
	};
	let thread_count: uint = match os::getenv("THREADS") {
		Some(v) => from_str(v).expect("THREADS expects integer"),
		None => 3,
	};
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let p = dir.path();
	let p = Path::new(".");

	let mut buffermanager = BufferManager::new(pages_in_ram, p.clone());

	for i in range(0, pages_on_disk) {
		let bf = match buffermanager.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page {}", i),
		};
		{
			let mut lock = bf.write();
			lock.get_mut_data()[0] = 0;
		}
		buffermanager.unfix_page(bf, true);
	}
	let bm = Arc::new(RWLock::new(buffermanager));

	// start scan thread
	let (tx, rx) = channel();
	let bm_scan = bm.clone();
	let mut scan = Future::spawn(proc() {
		let mut counters = Vec::from_elem(pages_on_disk as uint, 0_u8);
		loop {
			info!("Running scan thread...");
			match rx.try_recv() {
				Empty => {
					let page_number = randrange(pages_on_disk);
					let mut bm = bm_scan.write();
					let bf = match bm.fix_page(page_number) {
						Some(frame) => frame,
						None => fail!("Couldn't scan/fix page"),
					};
					let current_val = {
						let lock = bf.read();
						lock.get_data()[0]
					};
					bm.unfix_page(bf, false);
					bm.downgrade();
					// check if the value is going up
					assert!(&current_val >= counters.get(page_number as uint));
					// set to the new value
					let v = counters.get_mut(page_number as uint);
					*v = current_val;

				},
				/*
				 * terminate on both disconnect and when any kind of
				 * data arrives
				 */
				Disconnected => break,
				Data(_) => break,
			};
		}
	});

	// start read/write threads
	let mut rw_threads: Vec<Future<int>> = Vec::new();
	for _ in range(0, thread_count) {
		let bm = bm.clone();
		rw_threads.push(Future::spawn(proc() {
			let is_write = random::<bool>();
			info!("Creating new {} task",
				if is_write {"write"} else {"read"});
			let page_number = randrange(pages_on_disk);
			let mut bm = bm.write();
			if is_write {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				{
					let mut lock = bf.write();
					let data = lock.get_mut_data();
					data[0] = data[0] + 1;
					info!("Wrote to page {}", page_number);
					debug!("data: {}", Vec::from_slice(data));
				}
				bm.unfix_page(bf, is_write);
			} else {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				bm.unfix_page(bf, is_write);
			}
			// return whether we wrote (1) or read (0) as future
			if is_write {1} else {0}
		}));
	}

	// Rust does not have join, but we can wait on Futures which does the same
	let total_count = rw_threads.mut_iter().fold(0, |acc, val| acc + val.get());
	info!("Total count in RAM: {}", total_count);

	// terminate the scan thread and wait until it has completed
	tx.send("terminate");
	scan.get();

	// re-open the pages and check whether all numbers got saved
	let mut bm = BufferManager::new(pages_in_ram, p.clone());
	let mut total_count_on_disk = 0;
	for i in range(0, pages_on_disk) {
		let bf = match bm.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page")
		};
		let value = {
			let lock = bf.read();
			let data = lock.get_data();
			data[0]
		};
		bm.unfix_page(bf, false);
		// cast up from u8 to int
		total_count_on_disk += value as int;
	}
	info!("Total count on disk: {}", total_count_on_disk);
	assert_eq!(total_count, total_count_on_disk);
}
<|endoftext|>


<commit_before>//! Module containing functions for interacting with gluon's primitive types.
use std::string::String as StdString;
use std::result::Result as StdResult;

use {Variants, Error};
use primitives as prim;
use api::{generic, Generic, Getable, AsyncPushable, Array, RuntimeResult, primitive, WithVM};
use api::generic::A;
use gc::{Gc, Traverseable, DataDef, WriteOnly};
use Result;
use vm::{Thread, Status};
use value::{Def, GcStr, Value, ValueArray};
use stack::StackFrame;
use thread::ThreadInternal;
use types::VmInt;

fn array_length(array: Array<generic::A>) -> VmInt {
    array.len() as VmInt
}

fn array_index<'vm>(
    array: Array<'vm, Generic<generic::A>>,
    index: VmInt,
) -> RuntimeResult<Generic<generic::A>, String> {
    match array.get(index) {
        Some(value) => RuntimeResult::Return(value),
        None => RuntimeResult::Panic(format!("Index {} is out of range", index)),
    }
}

fn array_append<'vm>(
    lhs: Array<'vm, Generic<generic::A>>,
    rhs: Array<'vm, Generic<generic::A>>,
) -> RuntimeResult<Array<'vm, Generic<generic::A>>, Error> {
    struct Append<'b> {
        lhs: &'b ValueArray,
        rhs: &'b ValueArray,
    }

    impl<'b> Traverseable for Append<'b> {
        fn traverse(&self, gc: &mut Gc) {
            self.lhs.traverse(gc);
            self.rhs.traverse(gc);
        }
    }

    unsafe impl<'b> DataDef for Append<'b> {
        type Value = ValueArray;
        fn size(&self) -> usize {
            use std::mem::size_of;
            let len = self.lhs.len() + self.rhs.len();
            size_of::<usize>() + ::array::Array::<Value>::size_of(len)
        }
        fn initialize<'w>(self, mut result: WriteOnly<'w, ValueArray>) -> &'w mut ValueArray {
            // Empty arrays don't have the correct representation set so choose the representation
            // of `rhs` if it is empty. (And if both are empty the representation does not matter).
            let repr = if self.lhs.len() == 0 {
                self.rhs.repr()
            } else {
                self.lhs.repr()
            };
            unsafe {
                let result = &mut *result.as_mut_ptr();
                result.set_repr(repr);
                result.initialize(self.lhs.iter().chain(self.rhs.iter()));
                result
            }
        }
    }
    let vm = lhs.vm();
    let value = {
        let mut context = vm.context();
        let result = context.alloc(Append {
            lhs: &lhs,
            rhs: &rhs,
        });
        match result {
            Ok(x) => x,
            Err(err) => return RuntimeResult::Panic(err),
        }
    };
    unsafe {
        RuntimeResult::Return(
            Getable::from_value(lhs.vm(), Variants::new(&Value::Array(value))).expect("Array"),
        )
    }
}

fn string_append(lhs: WithVM<&str>, rhs: &str) -> RuntimeResult<String, Error> {
    struct StrAppend<'b> {
        lhs: &'b str,
        rhs: &'b str,
    }

    impl<'b> Traverseable for StrAppend<'b> {}

    unsafe impl<'b> DataDef for StrAppend<'b> {
        type Value = ValueArray;
        fn size(&self) -> usize {
            use std::mem::size_of;
            size_of::<ValueArray>() + (self.lhs.len() + self.rhs.len()) * size_of::<u8>()
        }
        fn initialize<'w>(self, mut result: WriteOnly<'w, ValueArray>) -> &'w mut ValueArray {
            use value::Repr;
            unsafe {
                let result = &mut *result.as_mut_ptr();
                result.set_repr(Repr::Byte);
                result.unsafe_array_mut::<u8>().initialize(
                    self.lhs
                        .as_bytes()
                        .iter()
                        .chain(self.rhs.as_bytes())
                        .cloned(),
                );
                result
            }
        }
    }

    let vm = lhs.vm;
    let lhs = lhs.value;
    unsafe {
        let mut context = vm.context();
        let result = context.alloc(StrAppend { lhs: lhs, rhs: rhs });
        let value = match result {
            Ok(x) => GcStr::from_utf8_unchecked(x),
            Err(err) => return RuntimeResult::Panic(err),
        };
        RuntimeResult::Return(
            Getable::from_value(vm, Variants::new(&Value::String(value))).expect("Array"),
        )
    }
}

fn string_slice(s: &str, start: usize, end: usize) -> RuntimeResult<&str, String> {
    if s.is_char_boundary(start) && s.is_char_boundary(end) {
        RuntimeResult::Return(&s[start..end])
    } else {
        // Limit the amount of characters to print in the error message
        let mut iter = s.chars();
        for _ in iter.by_ref().take(256) {}
        RuntimeResult::Panic(format!(
            "index {} and/or {} in `{}` does not lie on a character \
                                      boundary",
            start,
            end,
            &s[..(s.len() - iter.as_str().len())]
        ))
    }
}

extern "C" fn from_utf8(thread: &Thread) -> Status {
    let mut context = thread.context();
    let value = StackFrame::current(&mut context.stack)[0];
    match value {
        Value::Array(array) => {
            match GcStr::from_utf8(array) {
                Ok(string) => {
                    let value = Value::String(string);
                    let result = context.alloc_with(
                        thread,
                        Def {
                            tag: 1,
                            elems: &[value],
                        },
                    );
                    match result {
                        Ok(data) => {
                            context.stack.push(Value::Data(data));
                            Status::Ok
                        }
                        Err(err) => {
                            let result: RuntimeResult<(), _> = RuntimeResult::Panic(err);
                            result.status_push(thread, &mut context)
                        }
                    }
                }
                Err(()) =>{
                    let err: StdResult<&str, ()> = Err(());
                    err.status_push(thread, &mut context)
                }
            }
        }
        _ => unreachable!(),
    }
}

fn char_at(s: &str, index: usize) -> RuntimeResult<char, String> {
    if s.is_char_boundary(index) {
        if let Some(c) = s[index..].chars().next() {
            return RuntimeResult::Return(c);
        }
    }
    let mut iter = s.chars();
    for _ in iter.by_ref().take(256) {}
    RuntimeResult::Panic(format!(
        "index {} in `{}` does not lie on a character boundary",
        index,
        &s[..(s.len() - iter.as_str().len())]
    ))
}

fn show_int(i: VmInt) -> String {
    format!("{}", i)
}

fn show_float(f: f64) -> String {
    format!("{}", f)
}

fn show_char(c: char) -> String {
    format!("{}", c)
}

extern "C" fn error(_: &Thread) -> Status {
    // We expect a string as an argument to this function but we only return Status::Error
    // and let the caller take care of printing the message
    Status::Error
}

pub fn load(vm: &Thread) -> Result<()> {
    use std::f64;
    use std::char;
    vm.define_global(
        "float",
        record!(
        digits => f64::DIGITS,
        epsilon => f64::EPSILON,
        infinity => f64::INFINITY,
        mantissa_digits => f64::MANTISSA_DIGITS,
        max_ => f64::MAX,
        max_10_exp => f64::MAX_10_EXP,
        max_exp => f64::MAX_EXP,
        min_ => f64::MIN,
        min_10_exp => f64::MIN_10_EXP,
        min_exp => f64::MIN_EXP,
        min_positive => f64::MIN_POSITIVE,
        nan => f64::NAN,
        neg_infinity => f64::NEG_INFINITY,
        e => f64::consts::E,
        pi => f64::consts::PI,
        radix => f64::RADIX,
        is_nan => primitive!(1 f64::is_nan),
        is_infinite => primitive!(1 f64::is_infinite),
        is_finite => primitive!(1 f64::is_finite),
        is_normal => primitive!(1 f64::is_normal),
        floor => primitive!(1 f64::floor),
        ceil => primitive!(1 f64::ceil),
        round => primitive!(1 f64::round),
        trunc => primitive!(1 f64::trunc),
        fract => primitive!(1 f64::fract),
        abs => primitive!(1 f64::abs),
        signum => primitive!(1 f64::signum),
        is_sign_positive => primitive!(1 f64::is_sign_positive),
        is_sign_negative => primitive!(1 f64::is_sign_negative),
        mul_add => primitive!(3 f64::mul_add),
        recip => primitive!(1 f64::recip),
        powi => primitive!(2 f64::powi),
        powf => primitive!(2 f64::powf),
        sqrt => primitive!(1 f64::sqrt),
        exp => primitive!(1 f64::exp),
        exp2 => primitive!(1 f64::exp2),
        ln => primitive!(1 f64::ln),
        log2 => primitive!(1 f64::log2),
        log10 => primitive!(1 f64::log10),
        to_degrees => primitive!(1 f64::to_degrees),
        to_radians => primitive!(1 f64::to_radians),
        max => primitive!(2 f64::max),
        min => primitive!(2 f64::min),
        cbrt => primitive!(1 f64::cbrt),
        hypot => primitive!(2 f64::hypot),
        sin => primitive!(1 f64::sin),
        cos => primitive!(1 f64::cos),
        tan => primitive!(1 f64::tan),
        acos => primitive!(1 f64::acos),
        atan => primitive!(1 f64::atan),
        atan2 => primitive!(2 f64::atan2),
        sin_cos => primitive!(1 f64::sin_cos),
        exp_m1 => primitive!(1 f64::exp_m1),
        ln_1p => primitive!(1 f64::ln_1p),
        sinh => primitive!(1 f64::sinh),
        cosh => primitive!(1 f64::cosh),
        tanh => primitive!(1 f64::tanh),
        acosh => primitive!(1 f64::acosh),
        atanh => primitive!(1 f64::atanh)
    ),
    )?;
    vm.define_global(
        "int",
        record!(
        min_value => VmInt::min_value(),
        max_value => VmInt::max_value(),
        count_ones => primitive!(1 VmInt::count_ones),
        rotate_left => primitive!(2 VmInt::rotate_left),
        rotate_right => primitive!(2 VmInt::rotate_right),
        swap_bytes => primitive!(1 VmInt::swap_bytes),
        from_be => primitive!(1 VmInt::from_be),
        from_le => primitive!(1 VmInt::from_le),
        to_be => primitive!(1 VmInt::to_be),
        to_le => primitive!(1 VmInt::to_le),
        pow => primitive!(2 VmInt::pow),
        abs => primitive!(1 VmInt::abs),
        signum => primitive!(1 VmInt::signum),
        is_positive => primitive!(1 VmInt::is_positive),
        is_negative => primitive!(1 VmInt::is_negative)
    ),
    )?;
    vm.define_global(
        "array",
        record!(
        length => primitive!(1 prim::array_length),
        index => primitive!(2 prim::array_index),
        append => primitive!(2 prim::array_append)
    ),
    )?;

    vm.define_global("string_prim",
                       record!(
        length => primitive!(1 str::len),
        is_empty => primitive!(1 str::is_empty),
        split_at => primitive!(2 str::split_at),
        find => primitive!(2 str::find::<&str>),
        rfind => primitive!(2 str::rfind::<&str>),
        starts_with => primitive!(2 str::starts_with::<&str>),
        ends_with => primitive!(2 str::ends_with::<&str>),
        trim => primitive!(1 str::trim),
        trim_left => primitive!(1 str::trim_left),
        trim_right => primitive!(1 str::trim_right),
        compare => primitive!(2 str::cmp),
        append => primitive!(2 prim::string_append),
        eq => primitive!(2 <str as PartialEq>::eq),
        slice => primitive!(3 prim::string_slice),
        from_utf8 => primitive::<fn(Vec<u8>) -> StdResult<String, ()>>("from_utf8", prim::from_utf8),
        char_at => primitive!(2 prim::char_at),
        as_bytes => primitive!(1 str::as_bytes)
    ))?;
    vm.define_global(
        "char",
        record!(
        is_digit => primitive!(2 char::is_digit),
        to_digit => primitive!(2 char::to_digit),
        len_utf8 => primitive!(1 char::len_utf8),
        len_utf16 => primitive!(1 char::len_utf16),
        is_alphabetic => primitive!(1 char::is_alphabetic),
        is_lowercase => primitive!(1 char::is_lowercase),
        is_uppercase => primitive!(1 char::is_uppercase),
        is_whitespace => primitive!(1 char::is_whitespace),
        is_alphanumeric => primitive!(1 char::is_alphanumeric),
        is_control => primitive!(1 char::is_control),
        is_numeric => primitive!(1 char::is_numeric)
    ),
    )?;
    vm.define_global(
        "prim",
        record!(
        show_Int => primitive!(1 prim::show_int),
        show_Float => primitive!(1 prim::show_float),
        show_Char => primitive!(1 prim::show_char)
    ),
    )?;

    vm.define_global(
        "#error",
        primitive::<fn(StdString) -> Generic<A>>(
            "#error",
            prim::error,
        ),
    )?;
    vm.define_global(
        "error",
        primitive::<fn(StdString) -> Generic<A>>(
            "error",
            prim::error,
        ),
    )?;

    ::lazy::load(vm)?;
    ::reference::load(vm)?;
    Ok(())
}
<commit_msg>fix(vm): Only allocate enough memory for a ValueArray when appending arrays<commit_after>//! Module containing functions for interacting with gluon's primitive types.
use std::string::String as StdString;
use std::result::Result as StdResult;

use {Variants, Error};
use primitives as prim;
use api::{generic, Generic, Getable, AsyncPushable, Array, RuntimeResult, primitive, WithVM};
use api::generic::A;
use gc::{Gc, Traverseable, DataDef, WriteOnly};
use Result;
use vm::{Thread, Status};
use value::{Def, GcStr, Repr, Value, ValueArray};
use stack::StackFrame;
use thread::ThreadInternal;
use types::VmInt;

fn array_length(array: Array<generic::A>) -> VmInt {
    array.len() as VmInt
}

fn array_index<'vm>(
    array: Array<'vm, Generic<generic::A>>,
    index: VmInt,
) -> RuntimeResult<Generic<generic::A>, String> {
    match array.get(index) {
        Some(value) => RuntimeResult::Return(value),
        None => RuntimeResult::Panic(format!("Index {} is out of range", index)),
    }
}

fn array_append<'vm>(
    lhs: Array<'vm, Generic<generic::A>>,
    rhs: Array<'vm, Generic<generic::A>>,
) -> RuntimeResult<Array<'vm, Generic<generic::A>>, Error> {
    struct Append<'b> {
        lhs: &'b ValueArray,
        rhs: &'b ValueArray,
    }

    impl<'b> Append<'b> {
        fn repr(&self) -> Repr {
            // Empty arrays don't have the correct representation set so choose the representation
            // of `rhs` if it is empty. (And if both are empty the representation does not matter).
            if self.lhs.len() == 0 {
                self.rhs.repr()
            } else {
                self.lhs.repr()
            }
        }
    }

    impl<'b> Traverseable for Append<'b> {
        fn traverse(&self, gc: &mut Gc) {
            self.lhs.traverse(gc);
            self.rhs.traverse(gc);
        }
    }

    unsafe impl<'b> DataDef for Append<'b> {
        type Value = ValueArray;
        fn size(&self) -> usize {
            let len = self.lhs.len() + self.rhs.len();
            ValueArray::size_of(self.repr(), len)
        }
        fn initialize<'w>(self, mut result: WriteOnly<'w, ValueArray>) -> &'w mut ValueArray {
            unsafe {
                let result = &mut *result.as_mut_ptr();
                result.set_repr(self.repr());
                result.initialize(self.lhs.iter().chain(self.rhs.iter()));
                result
            }
        }
    }
    let vm = lhs.vm();
    let value = {
        let mut context = vm.context();
        let result = context.alloc(Append {
            lhs: &lhs,
            rhs: &rhs,
        });
        match result {
            Ok(x) => x,
            Err(err) => return RuntimeResult::Panic(err),
        }
    };
    unsafe {
        RuntimeResult::Return(
            Getable::from_value(lhs.vm(), Variants::new(&Value::Array(value))).expect("Array"),
        )
    }
}

fn string_append(lhs: WithVM<&str>, rhs: &str) -> RuntimeResult<String, Error> {
    struct StrAppend<'b> {
        lhs: &'b str,
        rhs: &'b str,
    }

    impl<'b> Traverseable for StrAppend<'b> {}

    unsafe impl<'b> DataDef for StrAppend<'b> {
        type Value = ValueArray;
        fn size(&self) -> usize {
            use std::mem::size_of;
            size_of::<ValueArray>() + (self.lhs.len() + self.rhs.len()) * size_of::<u8>()
        }
        fn initialize<'w>(self, mut result: WriteOnly<'w, ValueArray>) -> &'w mut ValueArray {
            use value::Repr;
            unsafe {
                let result = &mut *result.as_mut_ptr();
                result.set_repr(Repr::Byte);
                result.unsafe_array_mut::<u8>().initialize(
                    self.lhs
                        .as_bytes()
                        .iter()
                        .chain(self.rhs.as_bytes())
                        .cloned(),
                );
                result
            }
        }
    }

    let vm = lhs.vm;
    let lhs = lhs.value;
    unsafe {
        let mut context = vm.context();
        let result = context.alloc(StrAppend { lhs: lhs, rhs: rhs });
        let value = match result {
            Ok(x) => GcStr::from_utf8_unchecked(x),
            Err(err) => return RuntimeResult::Panic(err),
        };
        RuntimeResult::Return(
            Getable::from_value(vm, Variants::new(&Value::String(value))).expect("Array"),
        )
    }
}

fn string_slice(s: &str, start: usize, end: usize) -> RuntimeResult<&str, String> {
    if s.is_char_boundary(start) && s.is_char_boundary(end) {
        RuntimeResult::Return(&s[start..end])
    } else {
        // Limit the amount of characters to print in the error message
        let mut iter = s.chars();
        for _ in iter.by_ref().take(256) {}
        RuntimeResult::Panic(format!(
            "index {} and/or {} in `{}` does not lie on a character \
                                      boundary",
            start,
            end,
            &s[..(s.len() - iter.as_str().len())]
        ))
    }
}

extern "C" fn from_utf8(thread: &Thread) -> Status {
    let mut context = thread.context();
    let value = StackFrame::current(&mut context.stack)[0];
    match value {
        Value::Array(array) => {
            match GcStr::from_utf8(array) {
                Ok(string) => {
                    let value = Value::String(string);
                    let result = context.alloc_with(
                        thread,
                        Def {
                            tag: 1,
                            elems: &[value],
                        },
                    );
                    match result {
                        Ok(data) => {
                            context.stack.push(Value::Data(data));
                            Status::Ok
                        }
                        Err(err) => {
                            let result: RuntimeResult<(), _> = RuntimeResult::Panic(err);
                            result.status_push(thread, &mut context)
                        }
                    }
                }
                Err(()) =>{
                    let err: StdResult<&str, ()> = Err(());
                    err.status_push(thread, &mut context)
                }
            }
        }
        _ => unreachable!(),
    }
}

fn char_at(s: &str, index: usize) -> RuntimeResult<char, String> {
    if s.is_char_boundary(index) {
        if let Some(c) = s[index..].chars().next() {
            return RuntimeResult::Return(c);
        }
    }
    let mut iter = s.chars();
    for _ in iter.by_ref().take(256) {}
    RuntimeResult::Panic(format!(
        "index {} in `{}` does not lie on a character boundary",
        index,
        &s[..(s.len() - iter.as_str().len())]
    ))
}

fn show_int(i: VmInt) -> String {
    format!("{}", i)
}

fn show_float(f: f64) -> String {
    format!("{}", f)
}

fn show_char(c: char) -> String {
    format!("{}", c)
}

extern "C" fn error(_: &Thread) -> Status {
    // We expect a string as an argument to this function but we only return Status::Error
    // and let the caller take care of printing the message
    Status::Error
}

pub fn load(vm: &Thread) -> Result<()> {
    use std::f64;
    use std::char;
    vm.define_global(
        "float",
        record!(
        digits => f64::DIGITS,
        epsilon => f64::EPSILON,
        infinity => f64::INFINITY,
        mantissa_digits => f64::MANTISSA_DIGITS,
        max_ => f64::MAX,
        max_10_exp => f64::MAX_10_EXP,
        max_exp => f64::MAX_EXP,
        min_ => f64::MIN,
        min_10_exp => f64::MIN_10_EXP,
        min_exp => f64::MIN_EXP,
        min_positive => f64::MIN_POSITIVE,
        nan => f64::NAN,
        neg_infinity => f64::NEG_INFINITY,
        e => f64::consts::E,
        pi => f64::consts::PI,
        radix => f64::RADIX,
        is_nan => primitive!(1 f64::is_nan),
        is_infinite => primitive!(1 f64::is_infinite),
        is_finite => primitive!(1 f64::is_finite),
        is_normal => primitive!(1 f64::is_normal),
        floor => primitive!(1 f64::floor),
        ceil => primitive!(1 f64::ceil),
        round => primitive!(1 f64::round),
        trunc => primitive!(1 f64::trunc),
        fract => primitive!(1 f64::fract),
        abs => primitive!(1 f64::abs),
        signum => primitive!(1 f64::signum),
        is_sign_positive => primitive!(1 f64::is_sign_positive),
        is_sign_negative => primitive!(1 f64::is_sign_negative),
        mul_add => primitive!(3 f64::mul_add),
        recip => primitive!(1 f64::recip),
        powi => primitive!(2 f64::powi),
        powf => primitive!(2 f64::powf),
        sqrt => primitive!(1 f64::sqrt),
        exp => primitive!(1 f64::exp),
        exp2 => primitive!(1 f64::exp2),
        ln => primitive!(1 f64::ln),
        log2 => primitive!(1 f64::log2),
        log10 => primitive!(1 f64::log10),
        to_degrees => primitive!(1 f64::to_degrees),
        to_radians => primitive!(1 f64::to_radians),
        max => primitive!(2 f64::max),
        min => primitive!(2 f64::min),
        cbrt => primitive!(1 f64::cbrt),
        hypot => primitive!(2 f64::hypot),
        sin => primitive!(1 f64::sin),
        cos => primitive!(1 f64::cos),
        tan => primitive!(1 f64::tan),
        acos => primitive!(1 f64::acos),
        atan => primitive!(1 f64::atan),
        atan2 => primitive!(2 f64::atan2),
        sin_cos => primitive!(1 f64::sin_cos),
        exp_m1 => primitive!(1 f64::exp_m1),
        ln_1p => primitive!(1 f64::ln_1p),
        sinh => primitive!(1 f64::sinh),
        cosh => primitive!(1 f64::cosh),
        tanh => primitive!(1 f64::tanh),
        acosh => primitive!(1 f64::acosh),
        atanh => primitive!(1 f64::atanh)
    ),
    )?;
    vm.define_global(
        "int",
        record!(
        min_value => VmInt::min_value(),
        max_value => VmInt::max_value(),
        count_ones => primitive!(1 VmInt::count_ones),
        rotate_left => primitive!(2 VmInt::rotate_left),
        rotate_right => primitive!(2 VmInt::rotate_right),
        swap_bytes => primitive!(1 VmInt::swap_bytes),
        from_be => primitive!(1 VmInt::from_be),
        from_le => primitive!(1 VmInt::from_le),
        to_be => primitive!(1 VmInt::to_be),
        to_le => primitive!(1 VmInt::to_le),
        pow => primitive!(2 VmInt::pow),
        abs => primitive!(1 VmInt::abs),
        signum => primitive!(1 VmInt::signum),
        is_positive => primitive!(1 VmInt::is_positive),
        is_negative => primitive!(1 VmInt::is_negative)
    ),
    )?;
    vm.define_global(
        "array",
        record!(
        length => primitive!(1 prim::array_length),
        index => primitive!(2 prim::array_index),
        append => primitive!(2 prim::array_append)
    ),
    )?;

    vm.define_global("string_prim",
                       record!(
        length => primitive!(1 str::len),
        is_empty => primitive!(1 str::is_empty),
        split_at => primitive!(2 str::split_at),
        find => primitive!(2 str::find::<&str>),
        rfind => primitive!(2 str::rfind::<&str>),
        starts_with => primitive!(2 str::starts_with::<&str>),
        ends_with => primitive!(2 str::ends_with::<&str>),
        trim => primitive!(1 str::trim),
        trim_left => primitive!(1 str::trim_left),
        trim_right => primitive!(1 str::trim_right),
        compare => primitive!(2 str::cmp),
        append => primitive!(2 prim::string_append),
        eq => primitive!(2 <str as PartialEq>::eq),
        slice => primitive!(3 prim::string_slice),
        from_utf8 => primitive::<fn(Vec<u8>) -> StdResult<String, ()>>("from_utf8", prim::from_utf8),
        char_at => primitive!(2 prim::char_at),
        as_bytes => primitive!(1 str::as_bytes)
    ))?;
    vm.define_global(
        "char",
        record!(
        is_digit => primitive!(2 char::is_digit),
        to_digit => primitive!(2 char::to_digit),
        len_utf8 => primitive!(1 char::len_utf8),
        len_utf16 => primitive!(1 char::len_utf16),
        is_alphabetic => primitive!(1 char::is_alphabetic),
        is_lowercase => primitive!(1 char::is_lowercase),
        is_uppercase => primitive!(1 char::is_uppercase),
        is_whitespace => primitive!(1 char::is_whitespace),
        is_alphanumeric => primitive!(1 char::is_alphanumeric),
        is_control => primitive!(1 char::is_control),
        is_numeric => primitive!(1 char::is_numeric)
    ),
    )?;
    vm.define_global(
        "prim",
        record!(
        show_Int => primitive!(1 prim::show_int),
        show_Float => primitive!(1 prim::show_float),
        show_Char => primitive!(1 prim::show_char)
    ),
    )?;

    vm.define_global(
        "#error",
        primitive::<fn(StdString) -> Generic<A>>(
            "#error",
            prim::error,
        ),
    )?;
    vm.define_global(
        "error",
        primitive::<fn(StdString) -> Generic<A>>(
            "error",
            prim::error,
        ),
    )?;

    ::lazy::load(vm)?;
    ::reference::load(vm)?;
    Ok(())
}
<|endoftext|>