<commit_before>use crate::{
    config, db,
    models::Version,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use cargo_registry_markdown::text_to_html;
use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let base_config = Arc::new(config::Base::from_environment());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let base_config = base_config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(base_config.uploader(), &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(
                    header::CACHE_CONTROL,
                    header::HeaderValue::from_static(CACHE_CONTROL_README),
                );
                base_config
                    .uploader()
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    uploader: &Uploader,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let pkg_name = format!("{}-{}", krate_name, version.num);

    let location = uploader.crate_location(krate_name, &version.num.to_string());

    let location = match uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(
        header::USER_AGENT,
        header::HeaderValue::from_static(USER_AGENT),
    );
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!("[{}] Unable to fetch crate: {}", pkg_name, err);
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}] Failed to get a 200 response: {}",
            pkg_name,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let archive = Archive::new(reader);
    render_pkg_readme(archive, &pkg_name)
}

fn render_pkg_readme<R: Read>(mut archive: Archive<R>, pkg_name: &str) -> Option<String> {
    let mut entries = archive
        .entries()
        .unwrap_or_else(|_| panic!("[{}] Invalid tar archive entries", pkg_name));

    let manifest: Manifest = {
        let path = format!("{}/Cargo.toml", pkg_name);
        let contents = find_file_by_path(&mut entries, Path::new(&path), pkg_name)
            .unwrap_or_else(|| panic!("[{}] couldn't open file: Cargo.toml", pkg_name));
        toml::from_str(&contents)
            .unwrap_or_else(|_| panic!("[{}] Syntax error in manifest file", pkg_name))
    };

    let rendered = {
        let readme_path = manifest.package.readme.as_ref()?;
        let path = format!("{}/{}", pkg_name, readme_path);
        let contents = find_file_by_path(&mut entries, Path::new(&path), pkg_name)
            .unwrap_or_else(|| panic!("[{}] couldn't open file: {}", pkg_name, readme_path));
        text_to_html(
            &contents,
            readme_path,
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Debug, Deserialize)]
    struct Package {
        readme: Option<String>,
        repository: Option<String>,
    }

    #[derive(Debug, Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    pkg_name: &str,
) -> Option<String> {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })?
        .unwrap_or_else(|_| panic!("[{}] file is not present: {}", pkg_name, path.display()));

    let mut contents = String::new();
    file.read_to_string(&mut contents)
        .unwrap_or_else(|_| panic!("[{}] Couldn't read file contents", pkg_name));
    Some(contents)
}

#[cfg(test)]
mod tests {
    use std::io::Write;
    use tar;

    use super::render_pkg_readme;

    fn add_file<W: Write>(pkg: &mut tar::Builder<W>, path: &str, content: &[u8]) {
        let mut header = tar::Header::new_gnu();
        header.set_size(content.len() as u64);
        header.set_cksum();
        pkg.append_data(&mut header, path, content).unwrap();
    }

    #[test]
    fn test_render_pkg_readme() {
        let mut pkg = tar::Builder::new(vec![]);
        add_file(
            &mut pkg,
            "foo-0.0.1/Cargo.toml",
            br#"
[package]
readme = "README.md"
"#,
        );
        add_file(&mut pkg, "foo-0.0.1/README.md", b"readme");
        let serialized_archive = pkg.into_inner().unwrap();
        let result =
            render_pkg_readme(tar::Archive::new(&*serialized_archive), "foo-0.0.1").unwrap();
        assert!(result.contains("readme"))
    }

    #[test]
    fn test_render_pkg_readme_w_link() {
        let mut pkg = tar::Builder::new(vec![]);
        add_file(
            &mut pkg,
            "foo-0.0.1/Cargo.toml",
            br#"
[package]
readme = "README.md"
repository = "https://github.com/foo/foo"
"#,
        );
        add_file(
            &mut pkg,
            "foo-0.0.1/README.md",
            b"readme [link](./Other.md)",
        );
        let serialized_archive = pkg.into_inner().unwrap();
        let result =
            render_pkg_readme(tar::Archive::new(&*serialized_archive), "foo-0.0.1").unwrap();
        assert!(result.contains("\"https://github.com/foo/foo/blob/HEAD/./Other.md\""))
    }

    #[test]
    fn test_render_pkg_readme_not_at_root() {
        let mut pkg = tar::Builder::new(vec![]);
        add_file(
            &mut pkg,
            "foo-0.0.1/Cargo.toml",
            br#"
[package]
readme = "docs/README.md"
repository = "https://github.com/foo/foo"
"#,
        );
        add_file(
            &mut pkg,
            "foo-0.0.1/docs/README.md",
            b"docs/readme [link](./Other.md)",
        );
        let serialized_archive = pkg.into_inner().unwrap();
        let result =
            render_pkg_readme(tar::Archive::new(&*serialized_archive), "foo-0.0.1").unwrap();
        assert!(result.contains("docs/readme"));
        assert!(result.contains("\"https://github.com/foo/foo/blob/HEAD/docs/./Other.md\""))
    }
}
<commit_msg>admin::render_readmes: Support packages without READMEs<commit_after>use crate::{
    config, db,
    models::Version,
    schema::{crates, readme_renderings, versions},
    uploaders::Uploader,
};
use std::{io::Read, path::Path, sync::Arc, thread};

use cargo_registry_markdown::text_to_html;
use chrono::{TimeZone, Utc};
use clap::Clap;
use diesel::{dsl::any, prelude::*};
use flate2::read::GzDecoder;
use reqwest::{blocking::Client, header};
use tar::{self, Archive};

const CACHE_CONTROL_README: &str = "public,max-age=604800";
const USER_AGENT: &str = "crates-admin";

#[derive(Clap, Debug)]
#[clap(
    name = "render-readmes",
    about = "Iterates over every crate versions ever uploaded and (re-)renders their \
        readme using the readme renderer from the cargo_registry crate.",
    after_help = "Warning: this can take a lot of time."
)]
pub struct Opts {
    /// How many versions should be queried and processed at a time.
    #[clap(long, default_value = "25")]
    page_size: usize,

    /// Only rerender readmes that are older than this date.
    #[clap(long)]
    older_than: Option<String>,

    /// Only rerender readmes for the specified crate.
    #[clap(long = "crate")]
    crate_name: Option<String>,
}

pub fn run(opts: Opts) {
    let base_config = Arc::new(config::Base::from_environment());
    let conn = db::connect_now().unwrap();

    let start_time = Utc::now();

    let older_than = if let Some(ref time) = opts.older_than {
        Utc.datetime_from_str(time, "%Y-%m-%d %H:%M:%S")
            .expect("Could not parse --older-than argument as a time")
    } else {
        start_time
    };
    let older_than = older_than.naive_utc();

    println!("Start time:                   {}", start_time);
    println!("Rendering readmes older than: {}", older_than);

    let mut query = versions::table
        .inner_join(crates::table)
        .left_outer_join(readme_renderings::table)
        .filter(
            readme_renderings::rendered_at
                .lt(older_than)
                .or(readme_renderings::version_id.is_null()),
        )
        .select(versions::id)
        .into_boxed();

    if let Some(crate_name) = opts.crate_name {
        println!("Rendering readmes for {}", crate_name);
        query = query.filter(crates::name.eq(crate_name));
    }

    let version_ids: Vec<i32> = query.load(&conn).expect("error loading version ids");

    let total_versions = version_ids.len();
    println!("Rendering {} versions", total_versions);

    let page_size = opts.page_size;

    let total_pages = total_versions / page_size;
    let total_pages = if total_versions % page_size == 0 {
        total_pages
    } else {
        total_pages + 1
    };

    let client = Client::new();

    for (page_num, version_ids_chunk) in version_ids.chunks(page_size).enumerate() {
        println!(
            "= Page {} of {} ==================================",
            page_num + 1,
            total_pages
        );

        let versions: Vec<(Version, String)> = versions::table
            .inner_join(crates::table)
            .filter(versions::id.eq(any(version_ids_chunk)))
            .select((versions::all_columns, crates::name))
            .load(&conn)
            .expect("error loading versions");

        let mut tasks = Vec::with_capacity(page_size as usize);
        for (version, krate_name) in versions {
            Version::record_readme_rendering(version.id, &conn).unwrap_or_else(|_| {
                panic!(
                    "[{}-{}] Couldn't record rendering time",
                    krate_name, version.num
                )
            });
            let client = client.clone();
            let base_config = base_config.clone();
            let handle = thread::spawn(move || {
                println!("[{}-{}] Rendering README...", krate_name, version.num);
                let readme = get_readme(base_config.uploader(), &client, &version, &krate_name);
                if readme.is_none() {
                    return;
                }
                let readme = readme.unwrap();
                let content_length = readme.len() as u64;
                let content = std::io::Cursor::new(readme);
                let readme_path = format!("readmes/{0}/{0}-{1}.html", krate_name, version.num);
                let mut extra_headers = header::HeaderMap::new();
                extra_headers.insert(
                    header::CACHE_CONTROL,
                    header::HeaderValue::from_static(CACHE_CONTROL_README),
                );
                base_config
                    .uploader()
                    .upload(
                        &client,
                        &readme_path,
                        content,
                        content_length,
                        "text/html",
                        extra_headers,
                    )
                    .unwrap_or_else(|_| {
                        panic!(
                            "[{}-{}] Couldn't upload file to S3",
                            krate_name, version.num
                        )
                    });
            });
            tasks.push(handle);
        }
        for handle in tasks {
            if let Err(err) = handle.join() {
                println!("Thread panicked: {:?}", err);
            }
        }
    }
}

/// Renders the readme of an uploaded crate version.
fn get_readme(
    uploader: &Uploader,
    client: &Client,
    version: &Version,
    krate_name: &str,
) -> Option<String> {
    let pkg_name = format!("{}-{}", krate_name, version.num);

    let location = uploader.crate_location(krate_name, &version.num.to_string());

    let location = match uploader {
        Uploader::S3 { .. } => location,
        Uploader::Local => format!("http://localhost:8888/{}", location),
    };

    let mut extra_headers = header::HeaderMap::new();
    extra_headers.insert(
        header::USER_AGENT,
        header::HeaderValue::from_static(USER_AGENT),
    );
    let response = match client.get(&location).headers(extra_headers).send() {
        Ok(r) => r,
        Err(err) => {
            println!("[{}] Unable to fetch crate: {}", pkg_name, err);
            return None;
        }
    };

    if !response.status().is_success() {
        println!(
            "[{}] Failed to get a 200 response: {}",
            pkg_name,
            response.text().unwrap()
        );
        return None;
    }

    let reader = GzDecoder::new(response);
    let archive = Archive::new(reader);
    render_pkg_readme(archive, &pkg_name)
}

fn render_pkg_readme<R: Read>(mut archive: Archive<R>, pkg_name: &str) -> Option<String> {
    let mut entries = archive
        .entries()
        .unwrap_or_else(|_| panic!("[{}] Invalid tar archive entries", pkg_name));

    let manifest: Manifest = {
        let path = format!("{}/Cargo.toml", pkg_name);
        let contents = find_file_by_path(&mut entries, Path::new(&path), pkg_name)
            .unwrap_or_else(|| panic!("[{}] couldn't open file: Cargo.toml", pkg_name));
        toml::from_str(&contents)
            .unwrap_or_else(|_| panic!("[{}] Syntax error in manifest file", pkg_name))
    };

    let rendered = {
        let readme_path = manifest.package.readme.as_ref()?;
        let path = format!("{}/{}", pkg_name, readme_path);
        let contents = find_file_by_path(&mut entries, Path::new(&path), pkg_name)?;
        text_to_html(
            &contents,
            readme_path,
            manifest.package.repository.as_deref(),
        )
    };
    return Some(rendered);

    #[derive(Debug, Deserialize)]
    struct Package {
        readme: Option<String>,
        repository: Option<String>,
    }

    #[derive(Debug, Deserialize)]
    struct Manifest {
        package: Package,
    }
}

/// Search an entry by its path in a Tar archive.
fn find_file_by_path<R: Read>(
    entries: &mut tar::Entries<'_, R>,
    path: &Path,
    pkg_name: &str,
) -> Option<String> {
    let mut file = entries
        .find(|entry| match *entry {
            Err(_) => false,
            Ok(ref file) => {
                let filepath = match file.path() {
                    Ok(p) => p,
                    Err(_) => return false,
                };
                filepath == path
            }
        })?
        .unwrap_or_else(|_| panic!("[{}] file is not present: {}", pkg_name, path.display()));

    let mut contents = String::new();
    file.read_to_string(&mut contents)
        .unwrap_or_else(|_| panic!("[{}] Couldn't read file contents", pkg_name));
    Some(contents)
}

#[cfg(test)]
mod tests {
    use std::io::Write;
    use tar;

    use super::render_pkg_readme;

    fn add_file<W: Write>(pkg: &mut tar::Builder<W>, path: &str, content: &[u8]) {
        let mut header = tar::Header::new_gnu();
        header.set_size(content.len() as u64);
        header.set_cksum();
        pkg.append_data(&mut header, path, content).unwrap();
    }

    #[test]
    fn test_render_pkg_readme() {
        let mut pkg = tar::Builder::new(vec![]);
        add_file(
            &mut pkg,
            "foo-0.0.1/Cargo.toml",
            br#"
[package]
readme = "README.md"
"#,
        );
        add_file(&mut pkg, "foo-0.0.1/README.md", b"readme");
        let serialized_archive = pkg.into_inner().unwrap();
        let result =
            render_pkg_readme(tar::Archive::new(&*serialized_archive), "foo-0.0.1").unwrap();
        assert!(result.contains("readme"))
    }

    #[test]
    fn test_render_pkg_no_readme() {
        let mut pkg = tar::Builder::new(vec![]);
        add_file(
            &mut pkg,
            "foo-0.0.1/Cargo.toml",
            br#"
[package]
"#,
        );
        let serialized_archive = pkg.into_inner().unwrap();
        assert!(render_pkg_readme(tar::Archive::new(&*serialized_archive), "foo-0.0.1").is_none());
    }

    #[test]
    fn test_render_pkg_readme_w_link() {
        let mut pkg = tar::Builder::new(vec![]);
        add_file(
            &mut pkg,
            "foo-0.0.1/Cargo.toml",
            br#"
[package]
readme = "README.md"
repository = "https://github.com/foo/foo"
"#,
        );
        add_file(
            &mut pkg,
            "foo-0.0.1/README.md",
            b"readme [link](./Other.md)",
        );
        let serialized_archive = pkg.into_inner().unwrap();
        let result =
            render_pkg_readme(tar::Archive::new(&*serialized_archive), "foo-0.0.1").unwrap();
        assert!(result.contains("\"https://github.com/foo/foo/blob/HEAD/./Other.md\""))
    }

    #[test]
    fn test_render_pkg_readme_not_at_root() {
        let mut pkg = tar::Builder::new(vec![]);
        add_file(
            &mut pkg,
            "foo-0.0.1/Cargo.toml",
            br#"
[package]
readme = "docs/README.md"
repository = "https://github.com/foo/foo"
"#,
        );
        add_file(
            &mut pkg,
            "foo-0.0.1/docs/README.md",
            b"docs/readme [link](./Other.md)",
        );
        let serialized_archive = pkg.into_inner().unwrap();
        let result =
            render_pkg_readme(tar::Archive::new(&*serialized_archive), "foo-0.0.1").unwrap();
        assert!(result.contains("docs/readme"));
        assert!(result.contains("\"https://github.com/foo/foo/blob/HEAD/docs/./Other.md\""))
    }
}
<|endoftext|>


<commit_before>
use super::{
    EvalContext,
};
use error::{EvalResult, EvalError};
use rustc::ty;
use primval::PrimVal;
use memory::Pointer;

use rustc::ty::Ty;
use syntax::ast::{FloatTy, IntTy, UintTy};

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    pub(super) fn cast_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
        use primval::PrimValKind::*;
        match val.kind {
            F32 => self.cast_float(val.to_f32() as f64, ty),
            F64 => self.cast_float(val.to_f64(), ty),

            I8 | I16 | I32 | I64 => self.cast_signed_int(val.bits as i64, ty),

            Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false),

            FnPtr | Ptr => {
                let ptr = val.expect_ptr("FnPtr- or Ptr-tagged PrimVal had no relocation");
                self.cast_ptr(ptr, ty)
            }
        }
    }

    fn cast_signed_int(&self, val: i64, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
        self.cast_int(val as u64, ty, val < 0)
    }

    fn cast_int(&self, v: u64, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
        use primval::PrimValKind::*;
        use rustc::ty::TypeVariants::*;
        match ty.sty {
            TyBool if v == 0 => Ok(PrimVal::from_bool(false)),
            TyBool if v == 1 => Ok(PrimVal::from_bool(true)),
            TyBool => Err(EvalError::InvalidBool),

            TyInt(IntTy::I8)  => Ok(PrimVal::new(v as i64 as i8  as u64, I8)),
            TyInt(IntTy::I16) => Ok(PrimVal::new(v as i64 as i16 as u64, I16)),
            TyInt(IntTy::I32) => Ok(PrimVal::new(v as i64 as i32 as u64, I32)),
            TyInt(IntTy::I64) => Ok(PrimVal::new(v as i64 as i64 as u64, I64)),

            TyUint(UintTy::U8)  => Ok(PrimVal::new(v as u8  as u64, U8)),
            TyUint(UintTy::U16) => Ok(PrimVal::new(v as u16 as u64, U16)),
            TyUint(UintTy::U32) => Ok(PrimVal::new(v as u32 as u64, U32)),
            TyUint(UintTy::U64) => Ok(PrimVal::new(v, U64)),

            TyInt(IntTy::Is) => {
                let int_ty = self.tcx.sess.target.int_type;
                let ty = self.tcx.mk_mach_int(int_ty);
                self.cast_int(v, ty, negative)
            }

            TyUint(UintTy::Us) => {
                let uint_ty = self.tcx.sess.target.uint_type;
                let ty = self.tcx.mk_mach_uint(uint_ty);
                self.cast_int(v, ty, negative)
            }

            TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i64 as f64)),
            TyFloat(FloatTy::F64)             => Ok(PrimVal::from_f64(v as f64)),
            TyFloat(FloatTy::F32) if negative => Ok(PrimVal::from_f32(v as i64 as f32)),
            TyFloat(FloatTy::F32)             => Ok(PrimVal::from_f32(v as f32)),

            TyChar if v as u8 as u64 == v => Ok(PrimVal::new(v, Char)),
            TyChar => Err(EvalError::InvalidChar(v)),

            TyRawPtr(_) => Ok(PrimVal::from_ptr(Pointer::from_int(v as usize))),

            _ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
        }
    }

    fn cast_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
        use rustc::ty::TypeVariants::*;
        match ty.sty {
            // Casting negative floats to unsigned integers yields zero.
            TyUint(_) if val < 0.0 => self.cast_int(0, ty, false),
            TyInt(_)  if val < 0.0 => self.cast_int(val as i64 as u64, ty, true),

            TyInt(_) | ty::TyUint(_) => self.cast_int(val as u64, ty, false),

            TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(val)),
            TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(val as f32)),
            _ => Err(EvalError::Unimplemented(format!("float to {:?} cast", ty))),
        }
    }

    fn cast_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
        use rustc::ty::TypeVariants::*;
        match ty.sty {
            TyRef(..) | TyRawPtr(_) => Ok(PrimVal::from_ptr(ptr)),
            TyFnPtr(_) => Ok(PrimVal::from_fn_ptr(ptr)),

            TyInt(IntTy::I8) |
            TyInt(IntTy::I16) |
            TyInt(IntTy::I32) |
            TyInt(IntTy::I64) |
            TyInt(IntTy::Is) |
            TyUint(UintTy::U8) |
            TyUint(UintTy::U16) |
            TyUint(UintTy::U32) |
            TyUint(UintTy::U64) |
            TyUint(UintTy::Us) => {
                let val = PrimVal::from_ptr(ptr);
                self.transmute_primval(val, ty)
            }

            _ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
        }
    }
}
<commit_msg>Simplify cast_ptr.<commit_after>
use super::{
    EvalContext,
};
use error::{EvalResult, EvalError};
use rustc::ty;
use primval::PrimVal;
use memory::Pointer;

use rustc::ty::Ty;
use syntax::ast::{FloatTy, IntTy, UintTy};

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    pub(super) fn cast_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
        use primval::PrimValKind::*;
        match val.kind {
            F32 => self.cast_float(val.to_f32() as f64, ty),
            F64 => self.cast_float(val.to_f64(), ty),

            I8 | I16 | I32 | I64 => self.cast_signed_int(val.bits as i64, ty),

            Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false),

            FnPtr | Ptr => {
                let ptr = val.expect_ptr("FnPtr- or Ptr-tagged PrimVal had no relocation");
                self.cast_ptr(ptr, ty)
            }
        }
    }

    fn cast_signed_int(&self, val: i64, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
        self.cast_int(val as u64, ty, val < 0)
    }

    fn cast_int(&self, v: u64, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
        use primval::PrimValKind::*;
        use rustc::ty::TypeVariants::*;
        match ty.sty {
            TyBool if v == 0 => Ok(PrimVal::from_bool(false)),
            TyBool if v == 1 => Ok(PrimVal::from_bool(true)),
            TyBool => Err(EvalError::InvalidBool),

            TyInt(IntTy::I8)  => Ok(PrimVal::new(v as i64 as i8  as u64, I8)),
            TyInt(IntTy::I16) => Ok(PrimVal::new(v as i64 as i16 as u64, I16)),
            TyInt(IntTy::I32) => Ok(PrimVal::new(v as i64 as i32 as u64, I32)),
            TyInt(IntTy::I64) => Ok(PrimVal::new(v as i64 as i64 as u64, I64)),

            TyUint(UintTy::U8)  => Ok(PrimVal::new(v as u8  as u64, U8)),
            TyUint(UintTy::U16) => Ok(PrimVal::new(v as u16 as u64, U16)),
            TyUint(UintTy::U32) => Ok(PrimVal::new(v as u32 as u64, U32)),
            TyUint(UintTy::U64) => Ok(PrimVal::new(v, U64)),

            TyInt(IntTy::Is) => {
                let int_ty = self.tcx.sess.target.int_type;
                let ty = self.tcx.mk_mach_int(int_ty);
                self.cast_int(v, ty, negative)
            }

            TyUint(UintTy::Us) => {
                let uint_ty = self.tcx.sess.target.uint_type;
                let ty = self.tcx.mk_mach_uint(uint_ty);
                self.cast_int(v, ty, negative)
            }

            TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i64 as f64)),
            TyFloat(FloatTy::F64)             => Ok(PrimVal::from_f64(v as f64)),
            TyFloat(FloatTy::F32) if negative => Ok(PrimVal::from_f32(v as i64 as f32)),
            TyFloat(FloatTy::F32)             => Ok(PrimVal::from_f32(v as f32)),

            TyChar if v as u8 as u64 == v => Ok(PrimVal::new(v, Char)),
            TyChar => Err(EvalError::InvalidChar(v)),

            TyRawPtr(_) => Ok(PrimVal::from_ptr(Pointer::from_int(v as usize))),

            _ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
        }
    }

    fn cast_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
        use rustc::ty::TypeVariants::*;
        match ty.sty {
            // Casting negative floats to unsigned integers yields zero.
            TyUint(_) if val < 0.0 => self.cast_int(0, ty, false),
            TyInt(_)  if val < 0.0 => self.cast_int(val as i64 as u64, ty, true),

            TyInt(_) | ty::TyUint(_) => self.cast_int(val as u64, ty, false),

            TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(val)),
            TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(val as f32)),
            _ => Err(EvalError::Unimplemented(format!("float to {:?} cast", ty))),
        }
    }

    fn cast_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
        use rustc::ty::TypeVariants::*;
        match ty.sty {
            TyRef(..) | TyRawPtr(_) => Ok(PrimVal::from_ptr(ptr)),
            TyFnPtr(_) => Ok(PrimVal::from_fn_ptr(ptr)),
            TyInt(_) | TyUint(_) => self.transmute_primval(PrimVal::from_ptr(ptr), ty),
            _ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use ::error;
use ::Result;

pub type Handle = winapi::HANDLE;
pub type Mode = winapi::DWORD;
pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

/// Try to get the number of columns in the current terminal,
/// or assume 80 if it fails.
pub fn get_columns(handle: Handle) -> usize {
    let (cols, _) = get_win_size(handle);
    cols
}

/// Try to get the number of rows in the current terminal,
/// or assume 24 if it fails.
pub fn get_rows(handle: Handle) -> usize {
    let (_, rows) = get_win_size(handle);
    rows
}

fn get_win_size(handle: Handle) -> (usize, usize) {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => (80, 24),
        _ => (info.dwSize.X as usize, 1 + info.srWindow.Bottom - info.srWindow.Top),
    }
}

/// Checking for an unsupported TERM in windows is a no-op
pub fn is_unsupported_term() -> bool {
    false
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
pub fn is_a_tty(fd: winapi::DWORD) -> bool {
    let handle = get_std_handle(fd);
    match handle {
        Ok(handle) => {
            // If this function doesn't fail then fd is a TTY
            get_console_mode(handle).is_ok()
        }
        Err(_) => false,
    }
}

/// Enable raw mode for the TERM
pub fn enable_raw_mode() -> Result<Mode> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    let original_mode = try!(get_console_mode(handle));
    // Disable these modes
    let raw = original_mode &
              !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                winapi::wincon::ENABLE_PROCESSED_INPUT);
    // Enable these modes
    let raw = raw | winapi::wincon::ENABLE_EXTENDED_FLAGS;
    let raw = raw | winapi::wincon::ENABLE_INSERT_MODE;
    let raw = raw | winapi::wincon::ENABLE_QUICK_EDIT_MODE;
    let raw = raw | winapi::wincon::ENABLE_WINDOW_INPUT;
    check!(kernel32::SetConsoleMode(handle, raw));
    Ok(original_mode)
}

/// Disable Raw mode for the term
pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    check!(kernel32::SetConsoleMode(handle, original_mode));
    Ok(())
}

pub fn stdout_handle() -> Result<Handle> {
    let handle = try!(get_std_handle(STDOUT_FILENO));
    Ok(handle)
}

/// Clear the screen. Used to handle ctrl+l
pub fn clear_screen(_: &mut Write, handle: Handle) -> Result<()> {
    let mut info = unsafe { mem::zeroed() };
    check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info));
    let coord = winapi::COORD { X: 0, Y: 0 };
    check!(kernel32::SetConsoleCursorPosition(handle, coord));
    let mut _count = 0;
    let n = info.dwSize.X as winapi::DWORD * info.dwSize.Y as winapi::DWORD;
    check!(kernel32::FillConsoleOutputCharacterA(handle,
                                                 ' ' as winapi::CHAR,
                                                 n,
                                                 coord,
                                                 &mut _count));
    Ok(())
}

/// Console input reader
pub struct RawReader<R> {
    handle: winapi::HANDLE,
    buf: Option<u16>,
    phantom: PhantomData<R>,
}

impl<R: Read> RawReader<R> {
    pub fn new(_: R) -> Result<RawReader<R>> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(RawReader {
            handle: handle,
            buf: None,
            phantom: PhantomData,
        })
    }

    pub fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        use std::char::decode_utf16;
        // use winapi::{LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED};
        use winapi::{LEFT_ALT_PRESSED, RIGHT_ALT_PRESSED};

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        let mut esc_seen = false;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }

            // let alt_gr = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
            let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) ==
                      (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
            // let ctrl = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED);
            let meta = alt || esc_seen;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    _ => continue,
                };
            } else if utf16 == 27 {
                esc_seen = true;
                continue;
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    match c {
                        'b' | 'B' => return Ok(KeyPress::Meta('B')),
                        'c' | 'C' => return Ok(KeyPress::Meta('C')),
                        'd' | 'D' => return Ok(KeyPress::Meta('D')),
                        'f' | 'F' => return Ok(KeyPress::Meta('F')),
                        'l' | 'L' => return Ok(KeyPress::Meta('L')),
                        't' | 'T' => return Ok(KeyPress::Meta('T')),
                        'u' | 'U' => return Ok(KeyPress::Meta('U')),
                        'y' | 'Y' => return Ok(KeyPress::Meta('Y')),
                        _ => return Ok(KeyPress::UnknownEscSeq),
                    }
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl<R: Read> Iterator for RawReader<R> {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}

pub static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

pub fn install_sigwinch_handler() {
    // See ReadConsoleInputW && WINDOW_BUFFER_SIZE_EVENT
}
<commit_msg>Fix windows part<commit_after>use std::io;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use ::error;
use ::Result;

pub type Handle = winapi::HANDLE;
pub type Mode = winapi::DWORD;
pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

/// Try to get the number of columns in the current terminal,
/// or assume 80 if it fails.
pub fn get_columns(handle: Handle) -> usize {
    let (cols, _) = get_win_size(handle);
    cols
}

/// Try to get the number of rows in the current terminal,
/// or assume 24 if it fails.
pub fn get_rows(handle: Handle) -> usize {
    let (_, rows) = get_win_size(handle);
    rows
}

fn get_win_size(handle: Handle) -> (usize, usize) {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => (80, 24),
        _ => (info.dwSize.X as usize, (1 + info.srWindow.Bottom - info.srWindow.Top) as usize),
    }
}

/// Checking for an unsupported TERM in windows is a no-op
pub fn is_unsupported_term() -> bool {
    false
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
pub fn is_a_tty(fd: winapi::DWORD) -> bool {
    let handle = get_std_handle(fd);
    match handle {
        Ok(handle) => {
            // If this function doesn't fail then fd is a TTY
            get_console_mode(handle).is_ok()
        }
        Err(_) => false,
    }
}

/// Enable raw mode for the TERM
pub fn enable_raw_mode() -> Result<Mode> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    let original_mode = try!(get_console_mode(handle));
    // Disable these modes
    let raw = original_mode &
              !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                winapi::wincon::ENABLE_PROCESSED_INPUT);
    // Enable these modes
    let raw = raw | winapi::wincon::ENABLE_EXTENDED_FLAGS;
    let raw = raw | winapi::wincon::ENABLE_INSERT_MODE;
    let raw = raw | winapi::wincon::ENABLE_QUICK_EDIT_MODE;
    let raw = raw | winapi::wincon::ENABLE_WINDOW_INPUT;
    check!(kernel32::SetConsoleMode(handle, raw));
    Ok(original_mode)
}

/// Disable Raw mode for the term
pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    check!(kernel32::SetConsoleMode(handle, original_mode));
    Ok(())
}

pub fn stdout_handle() -> Result<Handle> {
    let handle = try!(get_std_handle(STDOUT_FILENO));
    Ok(handle)
}

/// Clear the screen. Used to handle ctrl+l
pub fn clear_screen(_: &mut Write, handle: Handle) -> Result<()> {
    let mut info = unsafe { mem::zeroed() };
    check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info));
    let coord = winapi::COORD { X: 0, Y: 0 };
    check!(kernel32::SetConsoleCursorPosition(handle, coord));
    let mut _count = 0;
    let n = info.dwSize.X as winapi::DWORD * info.dwSize.Y as winapi::DWORD;
    check!(kernel32::FillConsoleOutputCharacterA(handle,
                                                 ' ' as winapi::CHAR,
                                                 n,
                                                 coord,
                                                 &mut _count));
    Ok(())
}

/// Console input reader
pub struct RawReader<R> {
    handle: winapi::HANDLE,
    buf: Option<u16>,
    phantom: PhantomData<R>,
}

impl<R: Read> RawReader<R> {
    pub fn new(_: R) -> Result<RawReader<R>> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(RawReader {
            handle: handle,
            buf: None,
            phantom: PhantomData,
        })
    }

    pub fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        use std::char::decode_utf16;
        // use winapi::{LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED};
        use winapi::{LEFT_ALT_PRESSED, RIGHT_ALT_PRESSED};

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        let mut esc_seen = false;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }

            // let alt_gr = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
            let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) ==
                      (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
            // let ctrl = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED);
            let meta = alt || esc_seen;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    _ => continue,
                };
            } else if utf16 == 27 {
                esc_seen = true;
                continue;
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    match c {
                        'b' | 'B' => return Ok(KeyPress::Meta('B')),
                        'c' | 'C' => return Ok(KeyPress::Meta('C')),
                        'd' | 'D' => return Ok(KeyPress::Meta('D')),
                        'f' | 'F' => return Ok(KeyPress::Meta('F')),
                        'l' | 'L' => return Ok(KeyPress::Meta('L')),
                        't' | 'T' => return Ok(KeyPress::Meta('T')),
                        'u' | 'U' => return Ok(KeyPress::Meta('U')),
                        'y' | 'Y' => return Ok(KeyPress::Meta('Y')),
                        _ => return Ok(KeyPress::UnknownEscSeq),
                    }
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl<R: Read> Iterator for RawReader<R> {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}

pub static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

pub fn install_sigwinch_handler() {
    // See ReadConsoleInputW && WINDOW_BUFFER_SIZE_EVENT
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Error};

use ast::Stmt;

// For storing functions.
// In the future, this will have to store some sense of local variable scope,
// to deal with closures.
#[derive(Clone, Debug)]
pub struct JsFnStruct {
    pub name: Option<String>,
    pub params: Vec<String>,
    pub stmt: Stmt,
}

impl JsFnStruct {
    pub fn new(name: &Option<String>, params: &Vec<String>, block: &Stmt) -> JsFnStruct {
        JsFnStruct {
            name: name.clone(),
            params: params.clone(),
            stmt: block.clone(),
        }
    }
}

impl Display for JsFnStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "function {}(", self.name.clone().unwrap_or(String::new())));

        for (i, param) in self.params.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}", param));
        }

        try!(write!(fmt, ") {{\n"));
        try!(self.stmt.fmt_helper(&mut fmt, 2));
        write!(fmt, "\n}}")
    }
}

#[cfg(test)]
mod tests {
    // TODO tests for fn objs
}
<commit_msg>Change JsFn to use Vec<Stmt><commit_after>use std::fmt::{Display, Formatter, Error};

use ast::Stmt;

// For storing functions.
// In the future, this will have to store some sense of local variable scope,
// to deal with closures.
#[derive(Clone, Debug)]
pub struct JsFnStruct {
    pub name: Option<String>,
    pub params: Vec<String>,
    pub stmt: Vec<Stmt>,
}

impl JsFnStruct {
    pub fn new(name: &Option<String>, params: &Vec<String>, block: &Vec<Stmt>) -> JsFnStruct {
        JsFnStruct {
            name: name.clone(),
            params: params.clone(),
            stmt: block.clone(),
        }
    }
}

impl Display for JsFnStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "function {}(", self.name.clone().unwrap_or(String::new())));

        for (i, param) in self.params.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}", param));
        }

        try!(write!(fmt, ") {{\n"));
        for s in &self.stmt {
            try!(s.fmt_helper(&mut fmt, 2));
        }
        write!(fmt, "\n}}")
    }
}

#[cfg(test)]
mod tests {
    // TODO tests for fn objs
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A shareable mutable container for the DOM.

use dom::bindings::trace::JSTraceable;
use js::jsapi::{JSTracer};

use util::task_state;
use util::task_state::{SCRIPT, IN_GC};

use std::cell::{RefCell, Ref, RefMut};

/// A mutable field in the DOM.
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds.
pub struct DOMRefCell<T> {
    value: RefCell<T>,
}

// Functionality specific to Servo's `DOMRefCell` type
// ===================================================

impl<T> DOMRefCell<T> {
    /// Return a reference to the contents.
    ///
    /// For use in the layout task only.
    pub unsafe fn borrow_for_layout<'a>(&'a self) -> &'a T {
        debug_assert!(task_state::get().is_layout());
        &*self.value.as_unsafe_cell().get()
    }

    /// Borrow the contents for the purpose of GC tracing.
    ///
    /// This succeeds even if the object is mutably borrowed,
    /// so you have to be careful in trace code!
    pub unsafe fn borrow_for_gc_trace<'a>(&'a self) -> &'a T {
        debug_assert!(task_state::get().contains(SCRIPT | IN_GC));
        &*self.value.as_unsafe_cell().get()
    }

    /// Borrow the contents for the purpose of script deallocation.
    ///
    pub unsafe fn borrow_for_script_deallocation<'a>(&'a self) -> &'a mut T {
        debug_assert!(task_state::get().contains(SCRIPT));
        &mut *self.value.as_unsafe_cell().get()
    }

    /// Is the cell mutably borrowed?
    ///
    /// For safety checks in debug builds only.
    pub fn is_mutably_borrowed(&self) -> bool {
        self.value.try_borrow().is_some()
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        debug_assert!(task_state::get().is_script());
        self.value.try_borrow()
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        debug_assert!(task_state::get().is_script());
        self.value.try_borrow_mut()
    }
}

impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
    fn trace(&self, trc: *mut JSTracer) {
        (*self).borrow().trace(trc)
    }
}

// Functionality duplicated with `core::cell::RefCell`
// ===================================================
impl<T> DOMRefCell<T> {
    /// Create a new `DOMRefCell` containing `value`.
    pub fn new(value: T) -> DOMRefCell<T> {
        DOMRefCell {
            value: RefCell::new(value),
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    ///
    /// Panics if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => panic!("DOMRefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    ///
    /// Panics if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => panic!("DOMRefCell<T> already borrowed")
        }
    }
}
<commit_msg>auto merge of #4909 : saneyuki/servo/warn, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A shareable mutable container for the DOM.

use dom::bindings::trace::JSTraceable;
use js::jsapi::{JSTracer};

use util::task_state;
use util::task_state::{SCRIPT, IN_GC};

use std::cell::{BorrowState, RefCell, Ref, RefMut};

/// A mutable field in the DOM.
///
/// This extends the API of `core::cell::RefCell` to allow unsafe access in
/// certain situations, with dynamic checking in debug builds.
pub struct DOMRefCell<T> {
    value: RefCell<T>,
}

// Functionality specific to Servo's `DOMRefCell` type
// ===================================================

impl<T> DOMRefCell<T> {
    /// Return a reference to the contents.
    ///
    /// For use in the layout task only.
    pub unsafe fn borrow_for_layout<'a>(&'a self) -> &'a T {
        debug_assert!(task_state::get().is_layout());
        &*self.value.as_unsafe_cell().get()
    }

    /// Borrow the contents for the purpose of GC tracing.
    ///
    /// This succeeds even if the object is mutably borrowed,
    /// so you have to be careful in trace code!
    pub unsafe fn borrow_for_gc_trace<'a>(&'a self) -> &'a T {
        debug_assert!(task_state::get().contains(SCRIPT | IN_GC));
        &*self.value.as_unsafe_cell().get()
    }

    /// Borrow the contents for the purpose of script deallocation.
    ///
    pub unsafe fn borrow_for_script_deallocation<'a>(&'a self) -> &'a mut T {
        debug_assert!(task_state::get().contains(SCRIPT));
        &mut *self.value.as_unsafe_cell().get()
    }

    /// Is the cell mutably borrowed?
    ///
    /// For safety checks in debug builds only.
    pub fn is_mutably_borrowed(&self) -> bool {
        self.value.borrow_state() == BorrowState::Writing
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        debug_assert!(task_state::get().is_script());
        match self.value.borrow_state() {
            BorrowState::Writing => None,
            _ => Some(self.value.borrow()),
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        debug_assert!(task_state::get().is_script());
        match self.value.borrow_state() {
            BorrowState::Unused => Some(self.value.borrow_mut()),
            _ => None,
        }
    }
}

impl<T: JSTraceable> JSTraceable for DOMRefCell<T> {
    fn trace(&self, trc: *mut JSTracer) {
        (*self).borrow().trace(trc)
    }
}

// Functionality duplicated with `core::cell::RefCell`
// ===================================================
impl<T> DOMRefCell<T> {
    /// Create a new `DOMRefCell` containing `value`.
    pub fn new(value: T) -> DOMRefCell<T> {
        DOMRefCell {
            value: RefCell::new(value),
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    ///
    /// Panics if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => panic!("DOMRefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Panics
    ///
    /// Panics if this is called off the script thread.
    ///
    /// Panics if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => panic!("DOMRefCell<T> already borrowed")
        }
    }
}
<|endoftext|>


<commit_before>extern crate gmp;
use super::value::Value;

const COMMENT_CHAR:char = ';';
const ARGUMENT_CHAR:char = ',';

use super::environment::Environment;
use super::instruction::Instruction;
use super::instruction::create_instruction;
use super::util::*;
use std::collections::HashMap;

pub struct Assembler {
	code:       Vec<Box<Instruction>>,
	pub labels: HashMap<String, usize>,
	defines:    Vec<(String, String)>,
	pub ext_calls:  HashMap<String, Box<Fn(&Value, &mut Environment, &Assembler)>>
}

impl Assembler {
	fn parse_strings(&self, line:&String) -> String {
		let mut new_line:String = String::new();
		let mut is_literal_char = false;
		let mut is_in_stringval = false;
		for c in line.chars() {
			if !is_in_stringval && c == '"' {
				is_in_stringval = true;
				is_literal_char = false;
				new_line.push('b');
				continue;
			}
			if is_in_stringval {
				if c == '\\' && !is_literal_char {
					is_literal_char = true;
					continue;
				}
				if c == '"' && !is_literal_char {
					is_in_stringval = false;
					continue;
				}
				let mut char_add:char = c;
				if is_literal_char {
					char_add = match c {
						'\\' => '\\',
						'n'  => '\n',
						't'  => '\t',
						other => other
					};
					is_literal_char = false;
				}
				for b in char_to_boolvec(char_add) {
					new_line.push(match b {
						true => '1',
						false => '0'
					})
				}
			} else {
				new_line.push(c);
			}
		}
		return new_line;
	}

	pub fn add_external_call<F>(&mut self, name: &str, external: F)
		where F : 'static + Fn(&Value, &mut Environment, &Assembler) {

		self.ext_calls.insert(name.to_string(), Box::new(external));
	}

	pub fn new() -> Assembler {
		Assembler {
			code:      Vec::new(),
			labels:    HashMap::new(),
			defines:   Vec::new(),
			ext_calls: HashMap::new(),
		}
	}

	//private because reasons
	fn parse_args(&mut self, iname: &String, arguments: &[&str]){
		self.code.push(create_instruction(iname.as_ref(), arguments));
	}

	fn parse_macros(&mut self, line: &String) -> bool {
		//macro
		if line.chars().next() == Some('!') {
			let macro_text = line[1..].trim();
			let macro_args:Vec<&str> = macro_text.split_whitespace().collect();
			if macro_args.len() < 1 {
				panic!("Empty macro!");
			}
			match macro_args[0] {
				"define" => {
					if macro_args.len() < 3 {
						panic!("Macro 'define' requires at least 3 arguments!");
					}
					let name = macro_args[1].to_string();
					let args = macro_args[2..].join(" ");
					//println!("Defined '{}' as '{}'", name, args);
					self.defines.push((name, args));
				},
				name => panic!("Unknown macro name {}!", name)
			}
			return true;
		}
		return false;
	}

	fn parse_defines(&self, line:&String) -> String {
		let ret = line.split(",").map(|w|{
			return format!(" {} ,", w);
		}).collect::<String>();
		let len = ret.len();
		ret[0..(len-1)].split_whitespace().map(|w|{
			for def in &self.defines {
				if def.0 == w {
					return format!("{} ", def.1);
				}
			}
			return format!("{} ", w);
		}).collect::<String>()
	}

	fn parse_labels(&mut self, line:&String) -> bool {
		if line.chars().next() == Some('.') {
			let name = line[1..].to_string();
			self.labels.insert(name, self.code.len());
			return true;
		}
		return false;
	}

	pub fn parse_line(&mut self, linearg: &String) {
		//trim and remove comments
		let mut line:String = linearg.trim().to_string();
		remove_comments(&mut line, COMMENT_CHAR);

		//parse strings into 'b10101010' format
		line = self.parse_strings(&line);

		//use macros and labels
		if self.parse_macros(&line) {
			return;
		}
		if self.parse_labels(&line) {
			return;
		}

		line = self.parse_defines(&line);

		//parse name and arguments
		let mut arg_string:String = String::new();
		let name:String = match line.split_whitespace().next(){
			Some(val) => {val.to_string()},
			None => return,//No instruction, skip this line
		};
		match line.find(name.as_str()){
			Some(pos) => {arg_string = line[(pos+name.len())..].trim().to_string();}
			None => {},
		}
		let arg_vec:Vec<&str> = arg_string
			.split(ARGUMENT_CHAR)
			.map(|val|val.trim())
			.filter(|val|val.trim() != "")
			.collect();

		self.parse_args(&name, &arg_vec);
	}

	pub fn run(&mut self, env: &mut Environment) {
		let len = self.code.len();
		while env.instruction < len {
			let ins = &self.code[env.instruction];
			env.instruction += 1;
			ins.exec(env, self);
		}
	}
}
<commit_msg>added !include macro<commit_after>extern crate gmp;
use super::value::Value;

const COMMENT_CHAR:char = ';';
const ARGUMENT_CHAR:char = ',';

use super::environment::Environment;
use super::instruction::Instruction;
use super::instruction::create_instruction;
use super::util::*;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;

pub struct Assembler {
	code:       Vec<Box<Instruction>>,
	pub labels: HashMap<String, usize>,
	defines:    Vec<(String, String)>,
	pub ext_calls:  HashMap<String, Box<Fn(&Value, &mut Environment, &Assembler)>>
}

impl Assembler {
	fn parse_strings(&self, line:&String) -> String {
		let mut new_line:String = String::new();
		let mut is_literal_char = false;
		let mut is_in_stringval = false;
		for c in line.chars() {
			if !is_in_stringval && c == '"' {
				is_in_stringval = true;
				is_literal_char = false;
				new_line.push('b');
				continue;
			}
			if is_in_stringval {
				if c == '\\' && !is_literal_char {
					is_literal_char = true;
					continue;
				}
				if c == '"' && !is_literal_char {
					is_in_stringval = false;
					continue;
				}
				let mut char_add:char = c;
				if is_literal_char {
					char_add = match c {
						'\\' => '\\',
						'n'  => '\n',
						't'  => '\t',
						other => other
					};
					is_literal_char = false;
				}
				for b in char_to_boolvec(char_add) {
					new_line.push(match b {
						true => '1',
						false => '0'
					})
				}
			} else {
				new_line.push(c);
			}
		}
		return new_line;
	}

	pub fn add_external_call<F>(&mut self, name: &str, external: F)
		where F : 'static + Fn(&Value, &mut Environment, &Assembler) {

		self.ext_calls.insert(name.to_string(), Box::new(external));
	}

	pub fn new() -> Assembler {
		Assembler {
			code:      Vec::new(),
			labels:    HashMap::new(),
			defines:   Vec::new(),
			ext_calls: HashMap::new(),
		}
	}

	//private because reasons
	fn parse_args(&mut self, iname: &String, arguments: &[&str]){
		self.code.push(create_instruction(iname.as_ref(), arguments));
	}

	fn parse_macros(&mut self, line: &String) -> bool {
		//macro
		if line.chars().next() == Some('!') {
			let macro_text = line[1..].trim();
			let macro_args:Vec<&str> = macro_text.split_whitespace().collect();
			let macro_total_args:&str = &macro_text[macro_args[0].len()..].trim();
			if macro_args.len() < 1 {
				panic!("Empty macro!");
			}
			match macro_args[0] {
				"define" => {
					if macro_args.len() < 3 {
						panic!("Macro 'define' requires at least 3 arguments!");
					}
					let name = macro_args[1].to_string();
					let args = macro_args[2..].join(" ");
					//println!("Defined '{}' as '{}'", name, args);
					self.defines.push((name, args));
				},
				"include" => {
					let file = File::open(macro_total_args).unwrap();
					let buffer = BufReader::new(&file);
					for line in buffer.lines() {
						let l:String = line.unwrap();
						self.parse_line(&l);
					}
				},
				name => panic!("Unknown macro name {}!", name)
			}
			return true;
		}
		return false;
	}

	fn parse_defines(&self, line:&String) -> String {
		let ret = line.split(",").map(|w|{
			return format!(" {} ,", w);
		}).collect::<String>();
		let len = ret.len();
		ret[0..(len-1)].split_whitespace().map(|w|{
			for def in &self.defines {
				if def.0 == w {
					return format!("{} ", def.1);
				}
			}
			return format!("{} ", w);
		}).collect::<String>()
	}

	fn parse_labels(&mut self, line:&String) -> bool {
		if line.chars().next() == Some('.') {
			let name = line[1..].to_string();
			self.labels.insert(name, self.code.len());
			return true;
		}
		return false;
	}

	pub fn parse_line(&mut self, linearg: &String) {
		//trim and remove comments
		let mut line:String = linearg.trim().to_string();
		remove_comments(&mut line, COMMENT_CHAR);

		//parse strings into 'b10101010' format
		line = self.parse_strings(&line);

		//use macros and labels
		if self.parse_macros(&line) {
			return;
		}
		if self.parse_labels(&line) {
			return;
		}

		line = self.parse_defines(&line);

		//parse name and arguments
		let mut arg_string:String = String::new();
		let name:String = match line.split_whitespace().next(){
			Some(val) => {val.to_string()},
			None => return,//No instruction, skip this line
		};
		match line.find(name.as_str()){
			Some(pos) => {arg_string = line[(pos+name.len())..].trim().to_string();}
			None => {},
		}
		let arg_vec:Vec<&str> = arg_string
			.split(ARGUMENT_CHAR)
			.map(|val|val.trim())
			.filter(|val|val.trim() != "")
			.collect();

		self.parse_args(&name, &arg_vec);
	}

	pub fn run(&mut self, env: &mut Environment) {
		let len = self.code.len();
		while env.instruction < len {
			let ins = &self.code[env.instruction];
			env.instruction += 1;
			ins.exec(env, self);
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 stb_image::bindgen::*;

use std::any::Any;
use libc;
use libc::{c_void, c_int};
use std::slice::raw::from_buf_raw;

pub struct Image<T> {
    pub width   : uint,
    pub height  : uint,
    pub depth   : uint,
    pub data    : ~[T],
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: ~[T]) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

pub enum LoadResult {
    Error(~str),
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

impl LoadResult {
    pub fn from_result(res: Result<LoadResult,~Any>)-> LoadResult {
        match res {
            Ok(res) => res,
            Err(e)  => Error(e.to_str()),
        }
    }
}

pub fn load(path: &Path) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

fn load_internal<T>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = from_buf_raw(buf, (w * h * d) as uint);
        libc::free(buf as *mut c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: &Path, force_depth: uint, convert_hdr: bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let path_as_str = match path.as_str() {
            Some(s) => s,
            None => return Error("path is not valid utf8".to_owned()),
        };
        path_as_str.with_c_str(|bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(bytes,
                                        &mut width,
                                        &mut height,
                                        &mut depth,
                                        force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_loadf failed".to_owned())
                } else {
                    ImageF32(load_internal(buffer, width, height, depth))
                }
            } else {
                let buffer = stbi_load(bytes,
                                       &mut width,
                                       &mut height,
                                       &mut depth,
                                       force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_load failed".to_owned())
                } else {
                    ImageU8(load_internal(buffer, width, height, depth))
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        if !convert_hdr && stbi_is_hdr_from_memory(buffer.as_ptr(), buffer.len() as c_int) != 0 {
            let buffer = stbi_loadf_from_memory(buffer.as_ptr(),
                                                buffer.len() as c_int,
                                                &mut width,
                                                &mut height,
                                                &mut depth,
                                                force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_loadf_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageF32(load_internal(buffer, width, height, actual_depth))
            }
        } else {
            let buffer = stbi_load_from_memory(buffer.as_ptr(),
                                               buffer.len() as c_int,
                                               &mut width,
                                               &mut height,
                                               &mut depth,
                                               force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_load_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageU8(load_internal(buffer, width, height, actual_depth))
            }
        }
    }
}
<commit_msg>Replace ~ with Box<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 stb_image::bindgen::*;

use std::any::Any;
use libc;
use libc::{c_void, c_int};
use std::slice::raw::from_buf_raw;

pub struct Image<T> {
    pub width   : uint,
    pub height  : uint,
    pub depth   : uint,
    pub data    : ~[T],
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: ~[T]) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

pub enum LoadResult {
    Error(~str),
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

impl LoadResult {
    pub fn from_result(res: Result<LoadResult,Box<Any>>)-> LoadResult {
        match res {
            Ok(res) => res,
            Err(e)  => Error(e.to_str()),
        }
    }
}

pub fn load(path: &Path) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

fn load_internal<T>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = from_buf_raw(buf, (w * h * d) as uint);
        libc::free(buf as *mut c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: &Path, force_depth: uint, convert_hdr: bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let path_as_str = match path.as_str() {
            Some(s) => s,
            None => return Error("path is not valid utf8".to_owned()),
        };
        path_as_str.with_c_str(|bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(bytes,
                                        &mut width,
                                        &mut height,
                                        &mut depth,
                                        force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_loadf failed".to_owned())
                } else {
                    ImageF32(load_internal(buffer, width, height, depth))
                }
            } else {
                let buffer = stbi_load(bytes,
                                       &mut width,
                                       &mut height,
                                       &mut depth,
                                       force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_load failed".to_owned())
                } else {
                    ImageU8(load_internal(buffer, width, height, depth))
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        if !convert_hdr && stbi_is_hdr_from_memory(buffer.as_ptr(), buffer.len() as c_int) != 0 {
            let buffer = stbi_loadf_from_memory(buffer.as_ptr(),
                                                buffer.len() as c_int,
                                                &mut width,
                                                &mut height,
                                                &mut depth,
                                                force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_loadf_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageF32(load_internal(buffer, width, height, actual_depth))
            }
        } else {
            let buffer = stbi_load_from_memory(buffer.as_ptr(),
                                               buffer.len() as c_int,
                                               &mut width,
                                               &mut height,
                                               &mut depth,
                                               force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_load_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageU8(load_internal(buffer, width, height, actual_depth))
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::common::util::*;

#[test]
fn test_toupper() {
    new_ucmd!()
        .args(&["a-z", "A-Z"])
        .pipe_in("!abcd!")
        .run()
        .stdout_is("!ABCD!");
}

#[test]
fn test_small_set2() {
    new_ucmd!()
        .args(&["0-9", "X"])
        .pipe_in("@0123456789")
        .run()
        .stdout_is("@XXXXXXXXXX");
}

#[test]
fn test_unicode() {
    new_ucmd!()
        .args(&[", ┬─┬", "╯︵┻━┻"])
        .pipe_in("(,°□°）, ┬─┬")
        .run()
        .stdout_is("(╯°□°）╯︵┻━┻");
}

#[test]
fn test_delete() {
    new_ucmd!()
        .args(&["-d", "a-z"])
        .pipe_in("aBcD")
        .run()
        .stdout_is("BD");
}

#[test]
fn test_delete_complement() {
    new_ucmd!()
        .args(&["-d", "-c", "a-z"])
        .pipe_in("aBcD")
        .run()
        .stdout_is("ac");
}

#[test]
fn test_squeeze() {
    new_ucmd!()
        .args(&["-s", "a-z"])
        .pipe_in("aaBBcDcc")
        .run()
        .stdout_is("aBBcDc");
}

#[test]
fn test_squeeze_complement() {
    new_ucmd!()
        .args(&["-sc", "a-z"])
        .pipe_in("aaBBcDcc")
        .run()
        .stdout_is("aaBcDcc");
}

#[test]
fn test_delete_and_squeeze() {
    new_ucmd!()
        .args(&["-ds", "a-z", "A-Z"])
        .pipe_in("abBcB")
        .run()
        .stdout_is("B");
}

#[test]
fn test_delete_and_squeeze_complement() {
    new_ucmd!()
        .args(&["-dsc", "a-z", "A-Z"])
        .pipe_in("abBcB")
        .run()
        .stdout_is("abc");
}

#[test]
fn test_set1_longer_than_set2() {
    new_ucmd!()
        .args(&["abc", "xy"])
        .pipe_in("abcde")
        .run()
        .stdout_is("xyyde");
}

#[test]
fn test_set1_shorter_than_set2() {
    new_ucmd!()
        .args(&["ab", "xyz"])
        .pipe_in("abcde")
        .run()
        .stdout_is("xycde");
}

#[test]
fn test_truncate() {
    new_ucmd!()
        .args(&["-t", "abc", "xy"])
        .pipe_in("abcde")
        .run()
        .stdout_is("xycde");
}

#[test]
fn test_truncate_with_set1_shorter_than_set2() {
    new_ucmd!()
        .args(&["-t", "ab", "xyz"])
        .pipe_in("abcde")
        .run()
        .stdout_is("xycde");
}

#[test]
fn missing_args_fails() {
    let (_, mut ucmd) = at_and_ucmd!();
    let result = ucmd.run();

    assert!(!result.success);
    assert!(result.stderr.contains("missing operand"));
}

#[test]
fn missing_required_second_arg_fails() {
    let (_, mut ucmd) = at_and_ucmd!();
    let result = ucmd
        .args(&["foo"])
        .run();

    assert!(!result.success);
    assert!(result.stderr.contains("missing operand after"));
}
<commit_msg>refactor/polish ~ `cargo make format`<commit_after>use crate::common::util::*;

#[test]
fn test_toupper() {
    new_ucmd!()
        .args(&["a-z", "A-Z"])
        .pipe_in("!abcd!")
        .run()
        .stdout_is("!ABCD!");
}

#[test]
fn test_small_set2() {
    new_ucmd!()
        .args(&["0-9", "X"])
        .pipe_in("@0123456789")
        .run()
        .stdout_is("@XXXXXXXXXX");
}

#[test]
fn test_unicode() {
    new_ucmd!()
        .args(&[", ┬─┬", "╯︵┻━┻"])
        .pipe_in("(,°□°）, ┬─┬")
        .run()
        .stdout_is("(╯°□°）╯︵┻━┻");
}

#[test]
fn test_delete() {
    new_ucmd!()
        .args(&["-d", "a-z"])
        .pipe_in("aBcD")
        .run()
        .stdout_is("BD");
}

#[test]
fn test_delete_complement() {
    new_ucmd!()
        .args(&["-d", "-c", "a-z"])
        .pipe_in("aBcD")
        .run()
        .stdout_is("ac");
}

#[test]
fn test_squeeze() {
    new_ucmd!()
        .args(&["-s", "a-z"])
        .pipe_in("aaBBcDcc")
        .run()
        .stdout_is("aBBcDc");
}

#[test]
fn test_squeeze_complement() {
    new_ucmd!()
        .args(&["-sc", "a-z"])
        .pipe_in("aaBBcDcc")
        .run()
        .stdout_is("aaBcDcc");
}

#[test]
fn test_delete_and_squeeze() {
    new_ucmd!()
        .args(&["-ds", "a-z", "A-Z"])
        .pipe_in("abBcB")
        .run()
        .stdout_is("B");
}

#[test]
fn test_delete_and_squeeze_complement() {
    new_ucmd!()
        .args(&["-dsc", "a-z", "A-Z"])
        .pipe_in("abBcB")
        .run()
        .stdout_is("abc");
}

#[test]
fn test_set1_longer_than_set2() {
    new_ucmd!()
        .args(&["abc", "xy"])
        .pipe_in("abcde")
        .run()
        .stdout_is("xyyde");
}

#[test]
fn test_set1_shorter_than_set2() {
    new_ucmd!()
        .args(&["ab", "xyz"])
        .pipe_in("abcde")
        .run()
        .stdout_is("xycde");
}

#[test]
fn test_truncate() {
    new_ucmd!()
        .args(&["-t", "abc", "xy"])
        .pipe_in("abcde")
        .run()
        .stdout_is("xycde");
}

#[test]
fn test_truncate_with_set1_shorter_than_set2() {
    new_ucmd!()
        .args(&["-t", "ab", "xyz"])
        .pipe_in("abcde")
        .run()
        .stdout_is("xycde");
}

#[test]
fn missing_args_fails() {
    let (_, mut ucmd) = at_and_ucmd!();
    let result = ucmd.run();

    assert!(!result.success);
    assert!(result.stderr.contains("missing operand"));
}

#[test]
fn missing_required_second_arg_fails() {
    let (_, mut ucmd) = at_and_ucmd!();
    let result = ucmd.args(&["foo"]).run();

    assert!(!result.success);
    assert!(result.stderr.contains("missing operand after"));
}
<|endoftext|>