<commit_before>use std::io;
use std::path::{PathBuf, Path};
use std::fs::{read_dir, PathExt};
use std::borrow::ToOwned;
use std::iter::IteratorExt;
use std::cmp::Ordering;
use std::mem;

use super::super::comm::spmc::bounded_fast as spmc;
use super::super::iter_reduce::{Reduce, IteratorReduce};

use super::super::database::Database;
use super::super::Directory;
use super::super::error::{BonzoResult, BonzoError};

pub struct FileInfo {
    pub path: PathBuf,
    pub modified: u64,
    pub filename: String,
    pub directory: Directory
}

pub type FileInfoMessage = BonzoResult<FileInfo>;

struct FilePathExporter<'sender> {
    database: Database,
    channel: &'sender mut spmc::Producer<'static, FileInfoMessage>
}

impl<'sender> FilePathExporter<'sender> {
    // Recursively walks the given directory, processing all files within.
    // Deletes references to deleted files which were previously found from the
    // database. Processes files in descending order of last mutation.
    fn export_directory(&self, path: &Path, directory: Directory) -> BonzoResult<()> {
        let content_iter = try!(newest_first_walker(path, false));
        let mut deleted_filenames = try!(self.database.get_directory_filenames(directory));

        for item in content_iter {
            let (content_path, last_modified) = try!(item);

            let filename = try!(
                content_path
                    .file_name()
                    .and_then(|os_str| os_str.to_str())
                    .ok_or(BonzoError::from_str("Could not convert filename to string"))
                    .map(String::from_str)
            );

            if content_path.is_dir() {
                let child_directory = try!(self.database.get_directory(directory, &filename));

                try!(self.export_directory(&content_path, child_directory));
            }
            else {
                // FIXME: don't String::from_str if filename is dir
                if directory != Directory::Root || filename != super::super::DATABASE_FILENAME {
                    deleted_filenames.remove(&filename);

                    try!(
                        self.channel.send_sync(Ok(FileInfo {
                            path: content_path,
                            modified: last_modified,
                            filename: filename,
                            directory: directory
                        })).map_err(|_| BonzoError::from_str("Failed sending file path"))
                    );
                }
            }
        }

        deleted_filenames
            .iter()
            .map(|filename| {
                self.database
                    .persist_null_alias(directory, filename.as_slice())
                    .map_err(|e| BonzoError::Database(e))
            })
            .reduce()
    }
}

// TODO: move this function and export_directory to own module
pub fn send_files(source_path: &Path, database: Database, mut channel: spmc::Producer<'static, FileInfoMessage>) {
    let result = {
        let exporter = FilePathExporter {
            database: database,
            channel: &mut channel
        };

        exporter.export_directory(source_path, Directory::Root)
    };

    if let Err(e) = result {
        let _ = channel.send_sync(Err(e));
    }
}

// Walks the filesystem in an order that is defined by sort map, returning extra
// information along with the paths. Is guaranteed to return directories before
// their children
pub struct FilesystemWalker<'a, T: 'static> {
    cur: Vec<(PathBuf, T)>,
    file_map: &'a Fn(&Path) -> io::Result<T>,
    sort_map: &'a Fn(&(PathBuf, T), &(PathBuf, T)) -> Ordering,
    recursive: bool
}

impl<'a, T> Iterator for FilesystemWalker<'a, T> {
    type Item = io::Result<(PathBuf, T)>;

    fn next(&mut self) -> Option<io::Result<(PathBuf, T)>> {
        match self.cur.pop() {
            Some((path, extra)) => {
                if self.recursive && path.is_dir() {
                    match self.read_dir_sorted(&path) {
                        Err(e) => Some(Err(e)),
                        Ok(..) => Some(Ok((path, extra)))
                    }
                }
                else {
                    Some(Ok((path, extra)))
                }
            },
            None => None
        }
    }
}

impl<'a, T> FilesystemWalker<'a, T> {
    pub fn new<F, S>(dir: &Path, file_map: &'a F, sort_map: &'a S, recursive: bool) -> io::Result<FilesystemWalker<'a, T>>
           where F: Fn(&Path) -> io::Result<T>,
                 S: Fn(&(PathBuf, T), &(PathBuf, T)) -> Ordering {
        let mut walker = FilesystemWalker {
            cur: Vec::new(),
            file_map: file_map,
            sort_map: sort_map,
            recursive: recursive
        };

        try!(walker.read_dir_sorted(dir));

        Ok(walker)
    }

    fn read_dir_sorted(&mut self, dir: &Path) -> io::Result<()> {
        try!(
            read_dir(dir)
            .and_then(|list| list
                .map(|possible_entry| {
                    possible_entry.and_then(|entry| {
                        let path = entry.path();

                        (*self.file_map)(&path)
                            .map(|extra| {
                                let pair = (path.to_owned(), extra);
                                self.cur.push(pair);
                            })
                    })
                })
                .reduce()
            )
        );

        let other_self: &FilesystemWalker<'a, T> = unsafe { mem::transmute(&mut *self) };

        self.cur.sort_by(|a, b| (*other_self.sort_map)(a, b) );

        Ok(())
    }
}

// The idea here is that we serve the most recently changed files first
// because those are likely to be the most relevant.
pub struct NewestFirst<'a> {
    walker: FilesystemWalker<'a, u64>,
    #[allow(dead_code)]
    file_map: Box<Fn(&Path) -> io::Result<u64>>,
    #[allow(dead_code)]
    sort_map: Box<Fn(&(PathBuf, u64), &(PathBuf, u64)) -> Ordering>
}

impl<'a> Iterator for NewestFirst<'a> {
    type Item = io::Result<(PathBuf, u64)>;

    fn next(&mut self) -> Option<io::Result<(PathBuf, u64)>> {
        self.walker.next()
    }
}

pub fn newest_first_walker(dir: &Path, recursive: bool) -> io::Result<NewestFirst<'static>> {
    fn newest_first(a: &(PathBuf, u64), b: &(PathBuf, u64)) -> Ordering {
        let &(_, time_a) = a;
        let &(_, time_b) = b;

        time_a.cmp(&time_b)
    }

    fn modified_date(path: &Path) -> io::Result<u64> {
        path.metadata()
            .map(|stats| {
                stats.modified()
            })
    }

    let file_map = Box::new(modified_date);
    let sort_map = Box::new(newest_first);

    let walker: io::Result<FilesystemWalker<u64>> = FilesystemWalker::<u64>::new(
        dir,
        unsafe { mem::copy_lifetime("silly", &*file_map) },
        unsafe { mem::copy_lifetime("wadda", &*sort_map) },
        recursive
    );

    Ok(NewestFirst {
        walker: try!(walker),
        file_map: file_map,
        sort_map: sort_map
    })
}

#[cfg(test)]
mod test {
    use std::old_io::Timer;
    use std::time::Duration;
    use std::fs::create_dir_all;

    use super::super::super::tempdir::TempDir;
    use super::super::super::write_to_disk;

    #[test]
    fn read_dir() {
        let temp_dir = TempDir::new("readdir-test").unwrap();
        let root_path = temp_dir.path();
        let sub_dir = root_path.join("sub");

        create_dir_all(&sub_dir).unwrap();

        {
            let file_path = root_path.join("filezero");
            write_to_disk(&file_path, b"test123").unwrap();
        }

        Timer::new().unwrap().sleep(Duration::milliseconds(50));

        {
            let file_path = sub_dir.join("firstfile");
            write_to_disk(&file_path, b"yolo").unwrap();
        }

        Timer::new().unwrap().sleep(Duration::milliseconds(50));

        {
            let file_path = root_path.join("second");
            write_to_disk(&file_path, b"hello").unwrap();
        }

        Timer::new().unwrap().sleep(Duration::milliseconds(50));

        {
            let file_path = root_path.join("third");
            write_to_disk(&file_path, b"waddaa").unwrap();
        }

        Timer::new().unwrap().sleep(Duration::milliseconds(50));

        {
            let file_path = sub_dir.join("deadlast");
            write_to_disk(&file_path, b"plswork").unwrap();
        }

        let list = super::newest_first_walker(temp_dir.path(), true).unwrap();

        let filenames: Vec<String> = list
            .map(|x| {
                let (path, _) = x.unwrap();

                path.file_name().unwrap().to_string_lossy().into_owned()
            })
            .collect();

        assert_eq!(&["sub", "deadlast", "third", "second", "firstfile", "filezero"], &filenames);

        // TODO: add test for non-recursive case
    }
}
<commit_msg>extend test read_dir<commit_after>use std::io;
use std::path::{PathBuf, Path};
use std::fs::{read_dir, PathExt};
use std::borrow::ToOwned;
use std::iter::IteratorExt;
use std::cmp::Ordering;
use std::mem;

use super::super::comm::spmc::bounded_fast as spmc;
use super::super::iter_reduce::{Reduce, IteratorReduce};

use super::super::database::Database;
use super::super::Directory;
use super::super::error::{BonzoResult, BonzoError};

pub struct FileInfo {
    pub path: PathBuf,
    pub modified: u64,
    pub filename: String,
    pub directory: Directory
}

pub type FileInfoMessage = BonzoResult<FileInfo>;

struct FilePathExporter<'sender> {
    database: Database,
    channel: &'sender mut spmc::Producer<'static, FileInfoMessage>
}

impl<'sender> FilePathExporter<'sender> {
    // Recursively walks the given directory, processing all files within.
    // Deletes references to deleted files which were previously found from the
    // database. Processes files in descending order of last mutation.
    fn export_directory(&self, path: &Path, directory: Directory) -> BonzoResult<()> {
        let content_iter = try!(newest_first_walker(path, false));
        let mut deleted_filenames = try!(self.database.get_directory_filenames(directory));

        for item in content_iter {
            let (content_path, last_modified) = try!(item);

            let filename = try!(
                content_path
                    .file_name()
                    .and_then(|os_str| os_str.to_str())
                    .ok_or(BonzoError::from_str("Could not convert filename to string"))
                    .map(String::from_str)
            );

            if content_path.is_dir() {
                let child_directory = try!(self.database.get_directory(directory, &filename));

                try!(self.export_directory(&content_path, child_directory));
            }
            else {
                // FIXME: don't String::from_str if filename is dir
                if directory != Directory::Root || filename != super::super::DATABASE_FILENAME {
                    deleted_filenames.remove(&filename);

                    try!(
                        self.channel.send_sync(Ok(FileInfo {
                            path: content_path,
                            modified: last_modified,
                            filename: filename,
                            directory: directory
                        })).map_err(|_| BonzoError::from_str("Failed sending file path"))
                    );
                }
            }
        }

        deleted_filenames
            .iter()
            .map(|filename| {
                self.database
                    .persist_null_alias(directory, filename.as_slice())
                    .map_err(|e| BonzoError::Database(e))
            })
            .reduce()
    }
}

// TODO: move this function and export_directory to own module
pub fn send_files(source_path: &Path, database: Database, mut channel: spmc::Producer<'static, FileInfoMessage>) {
    let result = {
        let exporter = FilePathExporter {
            database: database,
            channel: &mut channel
        };

        exporter.export_directory(source_path, Directory::Root)
    };

    if let Err(e) = result {
        let _ = channel.send_sync(Err(e));
    }
}

// Walks the filesystem in an order that is defined by sort map, returning extra
// information along with the paths. Is guaranteed to return directories before
// their children
pub struct FilesystemWalker<'a, T: 'static> {
    cur: Vec<(PathBuf, T)>,
    file_map: &'a Fn(&Path) -> io::Result<T>,
    sort_map: &'a Fn(&(PathBuf, T), &(PathBuf, T)) -> Ordering,
    recursive: bool
}

impl<'a, T> Iterator for FilesystemWalker<'a, T> {
    type Item = io::Result<(PathBuf, T)>;

    fn next(&mut self) -> Option<io::Result<(PathBuf, T)>> {
        match self.cur.pop() {
            Some((path, extra)) => {
                if self.recursive && path.is_dir() {
                    match self.read_dir_sorted(&path) {
                        Err(e) => Some(Err(e)),
                        Ok(..) => Some(Ok((path, extra)))
                    }
                }
                else {
                    Some(Ok((path, extra)))
                }
            },
            None => None
        }
    }
}

impl<'a, T> FilesystemWalker<'a, T> {
    pub fn new<F, S>(dir: &Path, file_map: &'a F, sort_map: &'a S, recursive: bool) -> io::Result<FilesystemWalker<'a, T>>
           where F: Fn(&Path) -> io::Result<T>,
                 S: Fn(&(PathBuf, T), &(PathBuf, T)) -> Ordering {
        let mut walker = FilesystemWalker {
            cur: Vec::new(),
            file_map: file_map,
            sort_map: sort_map,
            recursive: recursive
        };

        try!(walker.read_dir_sorted(dir));

        Ok(walker)
    }

    fn read_dir_sorted(&mut self, dir: &Path) -> io::Result<()> {
        try!(
            read_dir(dir)
            .and_then(|list| list
                .map(|possible_entry| {
                    possible_entry.and_then(|entry| {
                        let path = entry.path();

                        (*self.file_map)(&path)
                            .map(|extra| {
                                let pair = (path.to_owned(), extra);
                                self.cur.push(pair);
                            })
                    })
                })
                .reduce()
            )
        );

        let other_self: &FilesystemWalker<'a, T> = unsafe { mem::transmute(&mut *self) };

        self.cur.sort_by(|a, b| (*other_self.sort_map)(a, b) );

        Ok(())
    }
}

// The idea here is that we serve the most recently changed files first
// because those are likely to be the most relevant.
pub struct NewestFirst<'a> {
    walker: FilesystemWalker<'a, u64>,
    #[allow(dead_code)]
    file_map: Box<Fn(&Path) -> io::Result<u64>>,
    #[allow(dead_code)]
    sort_map: Box<Fn(&(PathBuf, u64), &(PathBuf, u64)) -> Ordering>
}

impl<'a> Iterator for NewestFirst<'a> {
    type Item = io::Result<(PathBuf, u64)>;

    fn next(&mut self) -> Option<io::Result<(PathBuf, u64)>> {
        self.walker.next()
    }
}

pub fn newest_first_walker(dir: &Path, recursive: bool) -> io::Result<NewestFirst<'static>> {
    fn newest_first(a: &(PathBuf, u64), b: &(PathBuf, u64)) -> Ordering {
        let &(_, time_a) = a;
        let &(_, time_b) = b;

        time_a.cmp(&time_b)
    }

    fn modified_date(path: &Path) -> io::Result<u64> {
        path.metadata()
            .map(|stats| {
                stats.modified()
            })
    }

    let file_map = Box::new(modified_date);
    let sort_map = Box::new(newest_first);

    let walker: io::Result<FilesystemWalker<u64>> = FilesystemWalker::<u64>::new(
        dir,
        unsafe { mem::copy_lifetime("silly", &*file_map) },
        unsafe { mem::copy_lifetime("wadda", &*sort_map) },
        recursive
    );

    Ok(NewestFirst {
        walker: try!(walker),
        file_map: file_map,
        sort_map: sort_map
    })
}

#[cfg(test)]
mod test {
    use std::old_io::Timer;
    use std::time::Duration;
    use std::fs::create_dir_all;

    use super::super::super::tempdir::TempDir;
    use super::super::super::write_to_disk;

    #[test]
    fn read_dir() {
        let temp_dir = TempDir::new("readdir-test").unwrap();
        let root_path = temp_dir.path();
        let sub_dir = root_path.join("sub");

        create_dir_all(&sub_dir).unwrap();

        {
            let file_path = root_path.join("filezero");
            write_to_disk(&file_path, b"test123").unwrap();
        }

        Timer::new().unwrap().sleep(Duration::milliseconds(50));

        {
            let file_path = sub_dir.join("firstfile");
            write_to_disk(&file_path, b"yolo").unwrap();
        }

        Timer::new().unwrap().sleep(Duration::milliseconds(50));

        {
            let file_path = root_path.join("second");
            write_to_disk(&file_path, b"hello").unwrap();
        }

        Timer::new().unwrap().sleep(Duration::milliseconds(50));

        {
            let file_path = root_path.join("third");
            write_to_disk(&file_path, b"waddaa").unwrap();
        }

        Timer::new().unwrap().sleep(Duration::milliseconds(50));

        {
            let file_path = sub_dir.join("deadlast");
            write_to_disk(&file_path, b"plswork").unwrap();
        }

        let recursive_list = super::newest_first_walker(temp_dir.path(), true).unwrap();

        let all: Vec<String> = recursive_list
            .map(|x| {
                let (path, _) = x.unwrap();

                path.file_name().unwrap().to_string_lossy().into_owned()
            })
            .collect();

        assert_eq!(&["sub", "deadlast", "third", "second", "firstfile", "filezero"], &all);

        let flat_list = super::newest_first_walker(temp_dir.path(), true).unwrap();

        let directory: Vec<String> = flat_list
            .map(|x| {
                let (path, _) = x.unwrap();

                path.file_name().unwrap().to_string_lossy().into_owned()
            })
            .collect();

        assert_eq!(&["sub", "third", "second", "filezero"], &all);
    }
}
<|endoftext|>


<commit_before>use {Matrix2d, Field};

/// A polygon context.
pub struct PolygonContext<'a> {
    /// Base/origin transform.
    base: Field<'a, Matrix2d>,
    /// Current transform.
    transform: Field<'a, Matrix2d>,
    /// Current polygon.
    polygon: Field<'a, &'a [f64]>
}

<commit_msg>Implemented Transform2d for PolygonContext<commit_after>use {Matrix2d, Field, Value, Borrowed};
use vecmath::{multiply, translate, rotate_radians, scale, shear};
use {Transform2d};

/// A polygon context.
pub struct PolygonContext<'a> {
    /// Base/origin transform.
    base: Field<'a, Matrix2d>,
    /// Current transform.
    transform: Field<'a, Matrix2d>,
    /// Current polygon.
    polygon: Field<'a, &'a [f64]>
}

impl<'a> Transform2d<'a> for PolygonContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> PolygonContext<'a> {
        PolygonContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
        }
    }
}
<|endoftext|>


<commit_before>import platform::osmain;
import geometry::*;
import comm::*;
import image::base::Image;
import dl = layout::display_list;
import azure::*;
import azure::bindgen::*;
import libc::size_t;
import text::font::Font;
import text::text_run::TextRun;
import dom::event::{Event, ResizeEvent};
import geom::size::Size2D;
import geom::rect::Rect;
import geom::point::Point2D;
import azure_hl::AsAzureRect;
import ptr::addr_of;
import std::arc::arc;
import azure::cairo::{cairo_font_face_t, cairo_scaled_font_t};

import pipes::{port, chan};

type Renderer = comm::Chan<Msg>;

enum Msg {
    RenderMsg(dl::display_list),
    ExitMsg(pipes::chan<()>)
}

#[doc = "
The interface used to by the renderer to aquire draw targets for
each rendered frame and submit them to be drawn to the display

FIXME: Change this name to Compositor.
"]
trait Sink {
    fn begin_drawing(+next_dt: pipes::chan<AzDrawTargetRef>);
    fn draw(+next_dt: pipes::chan<AzDrawTargetRef>, draw_me: AzDrawTargetRef);
    fn add_event_listener(listener: comm::Chan<Event>);
}

fn Renderer<S: Sink send copy>(sink: S) -> comm::Chan<Msg> {
    do task::spawn_listener |po: comm::Port<Msg>| {
        let (draw_target_ch, draw_target_po) = pipes::stream();
        let mut draw_target_ch = draw_target_ch;
        let mut draw_target_po = draw_target_po;

        debug!("renderer: beginning rendering loop");

        sink.begin_drawing(draw_target_ch);

        loop {
            match po.recv() {
              RenderMsg(display_list) => {
                #debug("renderer: got render request");
                let draw_target = draw_target_po.recv();
                let (ch, po) = pipes::stream();
                let mut draw_target_ch_ = some(ch);
                draw_target_po = po;
                #debug("renderer: rendering");
                do util::time::time(~"rendering") {
                    let mut draw_target_ch = none;
                    draw_target_ch_ <-> draw_target_ch;
                    let draw_target_ch = option::unwrap(draw_target_ch);

                    clear(draw_target);
                    draw_display_list(draw_target, display_list);

                    #debug("renderer: returning surface");
                    sink.draw(draw_target_ch, draw_target);
                }
              }
              ExitMsg(response_ch) => {
                response_ch.send(());
                break;
              }
            }
        }
    }
}

trait to_float {
    fn to_float() -> float;
}

impl u8 : to_float {
    fn to_float() -> float {
        (self as float) / 255f
    }
}

fn draw_display_list(draw_target: AzDrawTargetRef, display_list: dl::display_list) {
    for display_list.each |item| {
        #debug["drawing %?", item];

        match item.item_type {
          dl::display_item_solid_color(r, g, b) => draw_solid_color(draw_target, item, r, g, b),
          dl::display_item_image(image) => draw_image(draw_target, item, *image),
          dl::display_item_text(text_run) => draw_text(draw_target, item, text_run),
          dl::padding(*) => fail ~"should never see padding"
        }
    }
}

fn draw_solid_color(draw_target: AzDrawTargetRef, item: dl::display_item,
                    r: u8, g: u8, b: u8) {
    let bounds = copy (*item).bounds;

    let red_color = {
        r: r.to_float() as AzFloat,
        g: g.to_float() as AzFloat,
        b: b.to_float() as AzFloat,
        a: 1f as AzFloat
    };
    let red_pattern = AzCreateColorPattern(ptr::addr_of(red_color));

    let red_rect = {
        x: au_to_px(bounds.origin.x) as AzFloat,
        y: au_to_px(bounds.origin.y) as AzFloat,
        width: au_to_px(bounds.size.width) as AzFloat,
        height: au_to_px(bounds.size.height) as AzFloat
    };
    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(red_rect),
        unsafe { unsafe::reinterpret_cast(red_pattern) }
    );

    AzReleaseColorPattern(red_pattern);
}

fn draw_image(draw_target: AzDrawTargetRef, item: dl::display_item, image: arc<~Image>) unsafe {
    let image = std::arc::get(&image);
    let size = Size2D(image.width as i32, image.height as i32);
    let stride = image.width * 4;

    // Do color space conversion :(
    let data = do vec::from_fn(image.width * image.height * 4) |i| {
        let color = i % 4;
        let pixel = i / 4;
        match color {
            0 => image.data[pixel * 3 + 2],
            1 => image.data[pixel * 3 + 1],
            2 => image.data[pixel * 3 + 0],
            3 => 0xffu8,
            _ => fail
        }
    };

    let azure_surface =
        AzDrawTargetCreateSourceSurfaceFromData(draw_target,
                                                addr_of(data[0]),
                                                unsafe::reinterpret_cast(addr_of(size)),
                                                stride as i32,
                                                0u32);
    let source_rect = Rect(Point2D(0.0f as AzFloat, 0.0f as AzFloat),
                           Size2D(image.width as AzFloat, image.height as AzFloat));
    let dest_rect = Rect(Point2D(au_to_px(item.bounds.origin.x) as AzFloat,
                                 au_to_px(item.bounds.origin.y) as AzFloat),
                         Size2D(au_to_px(item.bounds.size.width) as AzFloat,
                                au_to_px(item.bounds.size.height) as AzFloat));
    let draw_surface_options = azure_hl::DrawSurfaceOptions(azure_hl::Linear, true);
    let draw_options = azure_hl::DrawOptions(1.0f as AzFloat, 0);
    AzDrawTargetDrawSurface(draw_target,
                            azure_surface,
                            addr_of(dest_rect.as_azure_rect()),
                            addr_of(source_rect.as_azure_rect()),
                            addr_of(draw_surface_options.as_azure_draw_surface_options()),
                            addr_of(draw_options.as_azure_draw_options()));
    AzReleaseSourceSurface(azure_surface);
}

fn draw_text(draw_target: AzDrawTargetRef, item: dl::display_item, text_run: TextRun) {

    import ptr::{addr_of, null};
    import vec::unsafe::to_ptr;
    import libc::types::common::c99::{uint16_t, uint32_t};
    import geom::point::Point2D;
    import text::font_library::FontLibrary;
    import text::font::Font;
    import azure::{AzNativeFont, AzFloat, AZ_NATIVE_FONT_CAIRO_FONT_FACE};
    import azure::bindgen::{AzCreateScaledFontWithCairo,
                            AzReleaseScaledFont,
                            AzCreateColorPattern,
                            AzReleaseColorPattern};
    import azure::cairo::bindgen::cairo_scaled_font_destroy;

    let bounds = copy (*item).bounds;
    // FIXME: The font library should not be created here
    let flib = FontLibrary();
    let font = flib.get_test_font();

    let nfont: AzNativeFont = {
        mType: AZ_NATIVE_FONT_CAIRO_FONT_FACE,
        mFont: null()
    };

    let cfont = get_cairo_font(font);
    let azfont = AzCreateScaledFontWithCairo(addr_of(nfont), 1f as AzFloat, cfont);
    assert azfont.is_not_null();
    cairo_scaled_font_destroy(cfont);

    let color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let pattern = AzCreateColorPattern(addr_of(color));
    assert pattern.is_not_null();

    let options: AzDrawOptions = {
        mAlpha: 1f as AzFloat,
        fields: 0 as uint16_t
    };

    let mut origin = Point2D(bounds.origin.x, bounds.origin.y.add(bounds.size.height));
    let azglyphs = text_run.glyphs.map(|glyph| {
        let azglyph: AzGlyph = {
            mIndex: glyph.index as uint32_t,
            mPosition: {
                x: au_to_px(origin.x.add(glyph.pos.offset.x)) as AzFloat,
                y: au_to_px(origin.y.add(glyph.pos.offset.y)) as AzFloat
            }
        };
        origin = Point2D(origin.x.add(glyph.pos.advance.x),
                         origin.y.add(glyph.pos.advance.y));
        azglyph
    });

    let glyphbuf: AzGlyphBuffer = unsafe {{
        mGlyphs: to_ptr(azglyphs),
        mNumGlyphs: azglyphs.len() as uint32_t
    }};

    AzDrawTargetFillGlyphs(draw_target, azfont, addr_of(glyphbuf),
                           pattern, addr_of(options), null());

    AzReleaseColorPattern(pattern);
    AzReleaseScaledFont(azfont);
}

#[cfg(target_os = "linux")]
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {

    import libc::c_int;
    import azure::cairo_ft::bindgen::{cairo_ft_font_face_create_for_ft_face};

    let ftface = font.native_font.face;
    let cface = cairo_ft_font_face_create_for_ft_face(ftface, 0 as c_int);
    // FIXME: error handling
    return cface;
}

#[cfg(target_os = "macos")]
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {
    import azure::cairo_quartz::bindgen::cairo_quartz_font_face_create_for_cgfont;

    let cgfont = font.native_font.cgfont;
    let face = cairo_quartz_font_face_create_for_cgfont(cgfont);
    // FIXME: error handling
    return face;
}

fn get_cairo_font(font: &Font) -> *cairo_scaled_font_t {

    import libc::c_double;
    import azure::cairo;
    import cairo::cairo_matrix_t;
    import cairo::bindgen::{cairo_matrix_init_identity,
                            cairo_matrix_scale,
                            cairo_font_options_create,
                            cairo_scaled_font_create,
                            cairo_font_options_destroy,
                            cairo_font_face_destroy};

    // FIXME: error handling

    let face = get_cairo_face(font);

    let idmatrix: cairo_matrix_t = {
        xx: 0 as c_double,
        yx: 0 as c_double,
        xy: 0 as c_double,
        yy: 0 as c_double,
        x0: 0 as c_double,
        y0: 0 as c_double
    };
    cairo_matrix_init_identity(addr_of(idmatrix));

    let fontmatrix = idmatrix;
    cairo_matrix_scale(addr_of(fontmatrix),
                       20f as c_double, 20f as c_double);
    let options = cairo_font_options_create();
    let cfont = cairo_scaled_font_create(face, addr_of(fontmatrix),
                                         addr_of(idmatrix), options);
    cairo_font_options_destroy(options);
    cairo_font_face_destroy(face);

    return cfont;
}

fn clear(draw_target: AzDrawTargetRef) {

    let black_color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let black_pattern = AzCreateColorPattern(ptr::addr_of(black_color));

    let black_rect = {
        x: 0 as AzFloat,
        y: 0 as AzFloat,
        width: 800 as AzFloat,
        height: 600 as AzFloat,
    };

    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(black_rect),
        unsafe { unsafe::reinterpret_cast(black_pattern) }
    );

    AzReleaseColorPattern(black_pattern);
}
<commit_msg>Use the high level Azure API in the renderer some more<commit_after>import platform::osmain;
import geometry::*;
import comm::*;
import image::base::Image;
import dl = layout::display_list;
import azure::*;
import azure::bindgen::*;
import libc::size_t;
import text::font::Font;
import text::text_run::TextRun;
import dom::event::{Event, ResizeEvent};
import geom::size::Size2D;
import geom::rect::Rect;
import geom::point::Point2D;
import azure_hl::{AsAzureRect, Color, ColorPattern, DrawTarget};
import ptr::addr_of;
import std::arc::arc;
import azure::cairo::{cairo_font_face_t, cairo_scaled_font_t};

import pipes::{port, chan};

type Renderer = comm::Chan<Msg>;

enum Msg {
    RenderMsg(dl::display_list),
    ExitMsg(pipes::chan<()>)
}

#[doc = "
The interface used to by the renderer to aquire draw targets for
each rendered frame and submit them to be drawn to the display

FIXME: Change this name to Compositor.
"]
trait Sink {
    fn begin_drawing(+next_dt: pipes::chan<AzDrawTargetRef>);
    fn draw(+next_dt: pipes::chan<AzDrawTargetRef>, draw_me: AzDrawTargetRef);
    fn add_event_listener(listener: comm::Chan<Event>);
}

fn Renderer<S: Sink send copy>(sink: S) -> comm::Chan<Msg> {
    do task::spawn_listener |po: comm::Port<Msg>| {
        let (draw_target_ch, draw_target_po) = pipes::stream();
        let mut draw_target_ch = draw_target_ch;
        let mut draw_target_po = draw_target_po;

        debug!("renderer: beginning rendering loop");

        sink.begin_drawing(draw_target_ch);

        loop {
            match po.recv() {
              RenderMsg(display_list) => {
                #debug("renderer: got render request");
                let draw_target = draw_target_po.recv();
                let (ch, po) = pipes::stream();
                let mut draw_target_ch_ = some(ch);
                draw_target_po = po;
                #debug("renderer: rendering");
                do util::time::time(~"rendering") {
                    let mut draw_target_ch = none;
                    draw_target_ch_ <-> draw_target_ch;
                    let draw_target_ch = option::unwrap(draw_target_ch);

                    clear(draw_target);
                    draw_display_list(draw_target, display_list);

                    #debug("renderer: returning surface");
                    sink.draw(draw_target_ch, draw_target);
                }
              }
              ExitMsg(response_ch) => {
                response_ch.send(());
                break;
              }
            }
        }
    }
}

trait to_float {
    fn to_float() -> float;
}

impl u8 : to_float {
    fn to_float() -> float {
        (self as float) / 255f
    }
}

fn draw_display_list(azure_draw_target: AzDrawTargetRef, display_list: dl::display_list) {
    let draw_target = azure_hl::new_draw_target_from_azure_draw_target(azure_draw_target);
    for display_list.each |item| {
        #debug["drawing %?", item];

        match item.item_type {
          dl::display_item_solid_color(r, g, b) => draw_solid_color(&draw_target, item, r, g, b),
          dl::display_item_image(image) => draw_image(&draw_target, item, *image),
          dl::display_item_text(text_run) => draw_text(&draw_target, item, text_run),
          dl::padding(*) => fail ~"should never see padding"
        }
    }
}

fn draw_solid_color(draw_target: &DrawTarget, item: dl::display_item, r: u8, g: u8, b: u8) {
    let color = Color(r.to_float() as AzFloat,
                      g.to_float() as AzFloat,
                      b.to_float() as AzFloat,
                      1f as AzFloat);

    let pattern = ColorPattern(color);

    let rect = Rect(Point2D(au_to_px(item.bounds.origin.x) as AzFloat,
                            au_to_px(item.bounds.origin.y) as AzFloat),
                    Size2D(au_to_px(item.bounds.size.width) as AzFloat,
                           au_to_px(item.bounds.size.height) as AzFloat));

    draw_target.fill_rect(rect, pattern);
}

fn draw_image(draw_target: &DrawTarget, item: dl::display_item, image: arc<~Image>) unsafe {
    let draw_target = draw_target.azure_draw_target;

    let image = std::arc::get(&image);
    let size = Size2D(image.width as i32, image.height as i32);
    let stride = image.width * 4;

    // Do color space conversion :(
    let data = do vec::from_fn(image.width * image.height * 4) |i| {
        let color = i % 4;
        let pixel = i / 4;
        match color {
            0 => image.data[pixel * 3 + 2],
            1 => image.data[pixel * 3 + 1],
            2 => image.data[pixel * 3 + 0],
            3 => 0xffu8,
            _ => fail
        }
    };

    let azure_surface =
        AzDrawTargetCreateSourceSurfaceFromData(draw_target,
                                                addr_of(data[0]),
                                                unsafe::reinterpret_cast(addr_of(size)),
                                                stride as i32,
                                                0u32);
    let source_rect = Rect(Point2D(0.0f as AzFloat, 0.0f as AzFloat),
                           Size2D(image.width as AzFloat, image.height as AzFloat));
    let dest_rect = Rect(Point2D(au_to_px(item.bounds.origin.x) as AzFloat,
                                 au_to_px(item.bounds.origin.y) as AzFloat),
                         Size2D(au_to_px(item.bounds.size.width) as AzFloat,
                                au_to_px(item.bounds.size.height) as AzFloat));
    let draw_surface_options = azure_hl::DrawSurfaceOptions(azure_hl::Linear, true);
    let draw_options = azure_hl::DrawOptions(1.0f as AzFloat, 0);
    AzDrawTargetDrawSurface(draw_target,
                            azure_surface,
                            addr_of(dest_rect.as_azure_rect()),
                            addr_of(source_rect.as_azure_rect()),
                            addr_of(draw_surface_options.as_azure_draw_surface_options()),
                            addr_of(draw_options.as_azure_draw_options()));
    AzReleaseSourceSurface(azure_surface);
}

fn draw_text(draw_target: &DrawTarget, item: dl::display_item, text_run: TextRun) {
    import ptr::{addr_of, null};
    import vec::unsafe::to_ptr;
    import libc::types::common::c99::{uint16_t, uint32_t};
    import geom::point::Point2D;
    import text::font_library::FontLibrary;
    import text::font::Font;
    import azure::{AzNativeFont, AzFloat, AZ_NATIVE_FONT_CAIRO_FONT_FACE};
    import azure::bindgen::{AzCreateScaledFontWithCairo,
                            AzReleaseScaledFont,
                            AzCreateColorPattern,
                            AzReleaseColorPattern};
    import azure::cairo::bindgen::cairo_scaled_font_destroy;

    let draw_target = draw_target.azure_draw_target;

    let bounds = copy (*item).bounds;
    // FIXME: The font library should not be created here
    let flib = FontLibrary();
    let font = flib.get_test_font();

    let nfont: AzNativeFont = {
        mType: AZ_NATIVE_FONT_CAIRO_FONT_FACE,
        mFont: null()
    };

    let cfont = get_cairo_font(font);
    let azfont = AzCreateScaledFontWithCairo(addr_of(nfont), 1f as AzFloat, cfont);
    assert azfont.is_not_null();
    cairo_scaled_font_destroy(cfont);

    let color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let pattern = AzCreateColorPattern(addr_of(color));
    assert pattern.is_not_null();

    let options: AzDrawOptions = {
        mAlpha: 1f as AzFloat,
        fields: 0 as uint16_t
    };

    let mut origin = Point2D(bounds.origin.x, bounds.origin.y.add(bounds.size.height));
    let azglyphs = text_run.glyphs.map(|glyph| {
        let azglyph: AzGlyph = {
            mIndex: glyph.index as uint32_t,
            mPosition: {
                x: au_to_px(origin.x.add(glyph.pos.offset.x)) as AzFloat,
                y: au_to_px(origin.y.add(glyph.pos.offset.y)) as AzFloat
            }
        };
        origin = Point2D(origin.x.add(glyph.pos.advance.x),
                         origin.y.add(glyph.pos.advance.y));
        azglyph
    });

    let glyphbuf: AzGlyphBuffer = unsafe {{
        mGlyphs: to_ptr(azglyphs),
        mNumGlyphs: azglyphs.len() as uint32_t
    }};

    AzDrawTargetFillGlyphs(draw_target, azfont, addr_of(glyphbuf),
                           pattern, addr_of(options), null());

    AzReleaseColorPattern(pattern);
    AzReleaseScaledFont(azfont);
}

#[cfg(target_os = "linux")]
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {

    import libc::c_int;
    import azure::cairo_ft::bindgen::{cairo_ft_font_face_create_for_ft_face};

    let ftface = font.native_font.face;
    let cface = cairo_ft_font_face_create_for_ft_face(ftface, 0 as c_int);
    // FIXME: error handling
    return cface;
}

#[cfg(target_os = "macos")]
fn get_cairo_face(font: &Font) -> *cairo_font_face_t {
    import azure::cairo_quartz::bindgen::cairo_quartz_font_face_create_for_cgfont;

    let cgfont = font.native_font.cgfont;
    let face = cairo_quartz_font_face_create_for_cgfont(cgfont);
    // FIXME: error handling
    return face;
}

fn get_cairo_font(font: &Font) -> *cairo_scaled_font_t {

    import libc::c_double;
    import azure::cairo;
    import cairo::cairo_matrix_t;
    import cairo::bindgen::{cairo_matrix_init_identity,
                            cairo_matrix_scale,
                            cairo_font_options_create,
                            cairo_scaled_font_create,
                            cairo_font_options_destroy,
                            cairo_font_face_destroy};

    // FIXME: error handling

    let face = get_cairo_face(font);

    let idmatrix: cairo_matrix_t = {
        xx: 0 as c_double,
        yx: 0 as c_double,
        xy: 0 as c_double,
        yy: 0 as c_double,
        x0: 0 as c_double,
        y0: 0 as c_double
    };
    cairo_matrix_init_identity(addr_of(idmatrix));

    let fontmatrix = idmatrix;
    cairo_matrix_scale(addr_of(fontmatrix),
                       20f as c_double, 20f as c_double);
    let options = cairo_font_options_create();
    let cfont = cairo_scaled_font_create(face, addr_of(fontmatrix),
                                         addr_of(idmatrix), options);
    cairo_font_options_destroy(options);
    cairo_font_face_destroy(face);

    return cfont;
}

fn clear(draw_target: AzDrawTargetRef) {

    let black_color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let black_pattern = AzCreateColorPattern(ptr::addr_of(black_color));

    let black_rect = {
        x: 0 as AzFloat,
        y: 0 as AzFloat,
        width: 800 as AzFloat,
        height: 600 as AzFloat,
    };

    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(black_rect),
        unsafe { unsafe::reinterpret_cast(black_pattern) }
    );

    AzReleaseColorPattern(black_pattern);
}
<|endoftext|>


<commit_before>extern crate tempfile;
use tempfile::{NamedTempFile, NamedTempFileOptions};
use std::env;
use std::io::{Write, Read, Seek, SeekFrom};
use std::fs::File;
use std::path::Path;

fn exists<P: AsRef<Path>>(path: P) -> bool {
    std::fs::metadata(path.as_ref()).is_ok()
}

#[test]
fn test_basic() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    write!(tmpfile, "abcde").unwrap();
    tmpfile.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    tmpfile.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_deleted() {
    let tmpfile = NamedTempFile::new().unwrap();
    let path = tmpfile.path().to_path_buf();
    assert!(exists(&path));
    drop(tmpfile);
    assert!(!exists(&path));
}

#[test]
fn test_persist() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    let old_path = tmpfile.path().to_path_buf();
    let persist_path = env::temp_dir().join("persisted_temporary_file");
    write!(tmpfile, "abcde").unwrap();
    {
        assert!(exists(&old_path));
        let mut f = tmpfile.persist(&persist_path).unwrap();
        assert!(!exists(&old_path));

        // Check original file
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        f.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }

    {
        // Try opening it at the new path.
        let mut f = File::open(&persist_path).unwrap();
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        f.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }
    std::fs::remove_file(&persist_path).unwrap();
}

#[test]
fn test_persist_noclobber() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    let old_path = tmpfile.path().to_path_buf();
    let persist_target = NamedTempFile::new().unwrap();
    let persist_path = persist_target.path().to_path_buf();
    write!(tmpfile, "abcde").unwrap();
    assert!(exists(&old_path));
    {
        tmpfile = tmpfile.persist_noclobber(&persist_path).unwrap_err().into();
        assert!(exists(&old_path));
        std::fs::remove_file(&persist_path).unwrap();
        drop(persist_target);
    }
    tmpfile.persist_noclobber(&persist_path).unwrap();
    // Try opening it at the new path.
    let mut f = File::open(&persist_path).unwrap();
    f.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    f.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
    std::fs::remove_file(&persist_path).unwrap();
}

#[test]
fn test_customnamed() {
    let tmpfile = NamedTempFileOptions::new()
        .prefix("tmp")
        .suffix(&".rs".to_string())
        .rand_bytes(12)
        .create()
        .unwrap();
    let name = tmpfile.path().file_name().unwrap().to_str().unwrap();
    assert!(name.starts_with(("tmp")));
    assert!(name.ends_with(".rs"));
    assert_eq!(name.len(), 18);
}

#[test]
fn test_reopen() {
    let source = NamedTempFile::new().unwrap();
    let mut first = source.reopen().unwrap();
    let mut second = source.reopen().unwrap();
    drop(source);

    write!(first, "abcde").expect("write failed");
    let mut buf = String::new();
    second.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}
<commit_msg>Rustfmt tests<commit_after>extern crate tempfile;
use tempfile::{NamedTempFile, NamedTempFileOptions};
use std::env;
use std::io::{Write, Read, Seek, SeekFrom};
use std::fs::File;
use std::path::Path;

fn exists<P: AsRef<Path>>(path: P) -> bool {
    std::fs::metadata(path.as_ref()).is_ok()
}

#[test]
fn test_basic() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    write!(tmpfile, "abcde").unwrap();
    tmpfile.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    tmpfile.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_deleted() {
    let tmpfile = NamedTempFile::new().unwrap();
    let path = tmpfile.path().to_path_buf();
    assert!(exists(&path));
    drop(tmpfile);
    assert!(!exists(&path));
}

#[test]
fn test_persist() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    let old_path = tmpfile.path().to_path_buf();
    let persist_path = env::temp_dir().join("persisted_temporary_file");
    write!(tmpfile, "abcde").unwrap();
    {
        assert!(exists(&old_path));
        let mut f = tmpfile.persist(&persist_path).unwrap();
        assert!(!exists(&old_path));

        // Check original file
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        f.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }

    {
        // Try opening it at the new path.
        let mut f = File::open(&persist_path).unwrap();
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        f.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }
    std::fs::remove_file(&persist_path).unwrap();
}

#[test]
fn test_persist_noclobber() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    let old_path = tmpfile.path().to_path_buf();
    let persist_target = NamedTempFile::new().unwrap();
    let persist_path = persist_target.path().to_path_buf();
    write!(tmpfile, "abcde").unwrap();
    assert!(exists(&old_path));
    {
        tmpfile = tmpfile.persist_noclobber(&persist_path).unwrap_err().into();
        assert!(exists(&old_path));
        std::fs::remove_file(&persist_path).unwrap();
        drop(persist_target);
    }
    tmpfile.persist_noclobber(&persist_path).unwrap();
    // Try opening it at the new path.
    let mut f = File::open(&persist_path).unwrap();
    f.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    f.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
    std::fs::remove_file(&persist_path).unwrap();
}

#[test]
fn test_customnamed() {
    let tmpfile = NamedTempFileOptions::new()
                      .prefix("tmp")
                      .suffix(&".rs".to_string())
                      .rand_bytes(12)
                      .create()
                      .unwrap();
    let name = tmpfile.path().file_name().unwrap().to_str().unwrap();
    assert!(name.starts_with(("tmp")));
    assert!(name.ends_with(".rs"));
    assert_eq!(name.len(), 18);
}

#[test]
fn test_reopen() {
    let source = NamedTempFile::new().unwrap();
    let mut first = source.reopen().unwrap();
    let mut second = source.reopen().unwrap();
    drop(source);

    write!(first, "abcde").expect("write failed");
    let mut buf = String::new();
    second.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}
<|endoftext|>


<commit_before>extern crate varlink_generator;

use std::fs::File;
use std::io::prelude::*;
// use std::process::Command;

fn compare_files(a: std::path::PathBuf, b: std::path::PathBuf) -> bool {
    let fa = File::open(a).unwrap();
    let fb = File::open(b).unwrap();
    fa.bytes()
        .zip(fb.bytes())
        .all(|(a, b)| a.unwrap() == b.unwrap())
}

#[cfg(unix)]
#[test]
fn test_generate() {
    std::env::set_var("OUT_DIR", std::env::temp_dir());
    varlink_generator::cargo_build("tests/org.example.complex.varlink");
    let mut path = std::path::PathBuf::from(std::env::temp_dir());
    path.push("org.example.complex.rs");

    // assert!(
    // Command::new("rustfmt")
    // .arg(path.to_str().unwrap())
    // .output()
    // .is_ok()
    // );
    //
    if !compare_files(
        std::path::PathBuf::from("tests/org.example.complex.rs_out"),
        path.clone(),
    ) {
        panic!(
            "Generated files differ: '{}' versus '{}'",
            "tests/org.example.complex.rs_out",
            &path.to_str().unwrap()
        );
    }
    let _ = std::fs::remove_file(path);
}
<commit_msg>varlink_generator/tests/generator.rs: no windows "unused" warnings<commit_after>extern crate varlink_generator;

#[cfg(unix)]
#[test]
fn test_generate() {
    use std::fs::File;
    use std::io::prelude::*;
    // use std::process::Command;

    fn compare_files(a: std::path::PathBuf, b: std::path::PathBuf) -> bool {
        let fa = File::open(a).unwrap();
        let fb = File::open(b).unwrap();
        fa.bytes()
            .zip(fb.bytes())
            .all(|(a, b)| a.unwrap() == b.unwrap())
    }

    std::env::set_var("OUT_DIR", std::env::temp_dir());
    varlink_generator::cargo_build("tests/org.example.complex.varlink");
    let mut path = std::path::PathBuf::from(std::env::temp_dir());
    path.push("org.example.complex.rs");

    // assert!(
    // Command::new("rustfmt")
    // .arg(path.to_str().unwrap())
    // .output()
    // .is_ok()
    // );
    //
    if !compare_files(
        std::path::PathBuf::from("tests/org.example.complex.rs_out"),
        path.clone(),
    ) {
        panic!(
            "Generated files differ: '{}' versus '{}'",
            "tests/org.example.complex.rs_out",
            &path.to_str().unwrap()
        );
    }
    let _ = std::fs::remove_file(path);
}
<|endoftext|>


<commit_before>use std::rc::*;
use super::treenode::*;

///
/// Trait implemented by types that can work as a tree node index
///
pub trait TreeNodeIndex {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<'a>(&self, parent_node: &'a TreeNode) -> Option<&'a Rc<TreeNode>>;
}

impl TreeNodeIndex for usize {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<'a>(&self, parent_node: &'a TreeNode) -> Option<&'a Rc<TreeNode>> {
        let mut pos = *self;
        let mut current_child = parent_node.get_child_ref().to_owned();

        loop {
            match current_child {
                None        => return None,
                Some(child) => {
                    if pos == 0 { return current_child; }

                    pos = pos-1;
                    current_child = child.get_sibling_ref().to_owned();
                }
            }
        }
    }
}

///
/// Provides the ability to reference the children of a tree node by looking up a particular index
///
pub trait TreeNodeLookup : TreeNode {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<'a, TIndex: TreeNodeIndex>(&'a self, index: TIndex) -> &'a TreeNode;
}

impl<T: TreeNode> TreeNodeLookup for T {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<'a, TIndex: TreeNodeIndex>(&'a self, index: TIndex) -> &'a TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}

/*
impl<TIndex: TreeNodeIndex> Index<TIndex> for TreeNode {
    type Output = TreeNode;

    fn index<'a>(&'a self, index: TIndex) -> &'a TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}
*/

#[cfg(test)]
mod treenode_index_tests {
    use super::super::treenode::*;
    use super::super::basictree::*;
    use std::rc::*;

    #[test]
    fn lookup_usize() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        let lookup = 0.lookup_index(&tree);
        assert!(lookup.is_some());
        assert!(lookup.unwrap().get_tag() == "first_child");
        assert!(tree.get_sibling_ref().is_none());
    }

    #[test]
    fn can_get_first_child() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        assert!((tree.get_child_at(0).get_tag()) == "first_child");
        assert!(tree.get_sibling_ref().is_none());
    }
}
<commit_msg>We could now use this to implement the index trait for all tree nodes, but rust's generic's aren't up to it, it seems (would require that we put the definition in the same file as the Index trait).<commit_after>use std::rc::*;
use std::ops::*;
use super::treenode::*;

///
/// Trait implemented by types that can work as a tree node index
///
pub trait TreeNodeIndex {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<'a>(&self, parent_node: &'a TreeNode) -> Option<&'a Rc<TreeNode>>;
}

impl TreeNodeIndex for usize {
    ///
    /// Finds the tree node corresponding to the specified index in the tree
    ///
    fn lookup_index<'a>(&self, parent_node: &'a TreeNode) -> Option<&'a Rc<TreeNode>> {
        let mut pos = *self;
        let mut current_child = parent_node.get_child_ref().to_owned();

        loop {
            match current_child {
                None        => return None,
                Some(child) => {
                    if pos == 0 { return current_child; }

                    pos = pos-1;
                    current_child = child.get_sibling_ref().to_owned();
                }
            }
        }
    }
}

///
/// Provides the ability to reference the children of a tree node by looking up a particular index
///
pub trait TreeNodeLookup : TreeNode {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<'a, TIndex: TreeNodeIndex>(&'a self, index: TIndex) -> &'a TreeNode;
}

impl<T: TreeNode> TreeNodeLookup for T {
    ///
    /// Looks up a child node at a particular index (panics if the child does not exist)
    ///
    fn get_child_at<'a, TIndex: TreeNodeIndex>(&'a self, index: TIndex) -> &'a TreeNode {
        let opt_node = index.lookup_index(self);
        let node_ref = opt_node.unwrap();

        &**node_ref
    }
}

/*
impl<'b, T: TreeNode, TIndex: TreeNodeIndex> Index<TIndex> for T {
    type Output = TreeNode+'b;

    fn index<'a>(&'a self, index: TIndex) -> &'a TreeNode {
        self.get_child_at(index)
    }
}
*/

#[cfg(test)]
mod treenode_index_tests {
    use super::super::treenode::*;
    use super::super::basictree::*;
    use std::rc::*;

    #[test]
    fn lookup_usize() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        let lookup = 0.lookup_index(&tree);
        assert!(lookup.is_some());
        assert!(lookup.unwrap().get_tag() == "first_child");
        assert!(tree.get_sibling_ref().is_none());
    }

    #[test]
    fn can_get_first_child() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        assert!((tree.get_child_at(0).get_tag()) == "first_child");
        assert!(tree.get_sibling_ref().is_none());
    }

    /*
    #[test]
    fn can_get_first_child_via_index() {
        let mut tree = BasicTree::new("test", ());
        let first_child = Rc::new(BasicTree::new("first_child", ()));

        tree.set_child_ref(first_child);

        assert!((tree[0].get_tag()) == "first_child");
        assert!(tree.get_sibling_ref().is_none());
    }
    */
}
<|endoftext|>


<commit_before>extern crate curl;
extern crate flate2;
extern crate pkg_config;
extern crate semver;
extern crate tar;

use std::error::Error;
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use std::{env, fs};

use curl::easy::Easy;
use flate2::read::GzDecoder;
use semver::Version;
use tar::Archive;

const LIBRARY: &'static str = "tensorflow";
const REPOSITORY: &'static str = "https://github.com/tensorflow/tensorflow.git";
const TARGET: &'static str = "tensorflow:libtensorflow.so";
// `VERSION` and `TAG` are separate because the tag is not always `'v' + VERSION`.
const VERSION: &'static str = "1.0.0";
const TAG: &'static str = "v1.0.0";
const MIN_BAZEL: &'static str = "0.3.2";

macro_rules! get(($name:expr) => (ok!(env::var($name))));
macro_rules! ok(($expression:expr) => ($expression.unwrap()));
macro_rules! log {
    ($fmt:expr) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt), line!()));
    ($fmt:expr, $($arg:tt)*) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt),
    line!(), $($arg)*));
}
macro_rules! log_var(($var:ident) => (log!(concat!(stringify!($var), " = {:?}"), $var)));

fn main() {
    if pkg_config::find_library(LIBRARY).is_ok() {
        log!("Returning early because {} was already found", LIBRARY);
        return;
    }

    let force_src = match env::var("TF_RUST_BUILD_FROM_SRC") {
        Ok(s) => s == "true",
        Err(_) => false,
    };
    if !force_src && env::consts::ARCH == "x86_64" && (env::consts::OS == "linux" || env::consts::OS == "macos") {
        install_prebuilt();
    } else {
        build_from_src();
    }
}

fn remove_suffix(value: &mut String, suffix: &str) {
    if value.ends_with(suffix) {
        let n = value.len();
        value.truncate(n - suffix.len());
    }
}

fn extract<P: AsRef<Path>, P2: AsRef<Path>>(archive_path: P, extract_to: P2) {
    let file = File::open(archive_path).unwrap();
    let unzipped = GzDecoder::new(file).unwrap();
    let mut a = Archive::new(unzipped);
    a.unpack(extract_to).unwrap();
}

// Downloads and unpacks a prebuilt binary. Only works for certain platforms.
fn install_prebuilt() {
    // Figure out the file names.
    let os = match env::consts::OS {
        "macos" => "darwin",
        x => x,
    };
    let proc_type = if cfg!(feature = "tensorflow_gpu") {"gpu"} else {"cpu"};
    let binary_url = format!(
        "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-{}-{}-{}-{}.tar.gz",
        proc_type, os, env::consts::ARCH, VERSION);
    log_var!(binary_url);
    let short_file_name = binary_url.split("/").last().unwrap();
    let mut base_name = short_file_name.to_string();
    remove_suffix(&mut base_name, ".tar.gz");
    log_var!(base_name);
    let target_dir = PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join("target");
    if !target_dir.exists() {
        fs::create_dir(&target_dir).unwrap();
    }
    let file_name = target_dir.join(short_file_name);
    log_var!(file_name);

    // Download the tarball.
    if !file_name.exists() {
        let f = File::create(&file_name).unwrap();
        let mut writer = BufWriter::new(f);
        let mut easy = Easy::new();
        easy.url(&binary_url).unwrap();
        easy.write_function(move |data| {
            Ok(writer.write(data).unwrap())
        }).unwrap();
        easy.perform().unwrap();

        let response_code = easy.response_code().unwrap();
        if response_code != 200 {
            panic!("Unexpected response code {} for {}", response_code, binary_url);
        }
    }

    // Extract the tarball.
    let unpacked_dir = target_dir.join(base_name);
    let lib_dir = unpacked_dir.join("lib");
    if !lib_dir.join(format!("lib{}.so", LIBRARY)).exists() {
        extract(file_name, &unpacked_dir);
    }

    //run("find", |command| command); // TODO: remove
    run("ls", |command| {
        command.arg("-l").arg(lib_dir.to_str().unwrap())
        }); // TODO: remove

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", lib_dir.display());
}

fn build_from_src() {
    let output = PathBuf::from(&get!("OUT_DIR"));
    log_var!(output);
    let source = PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join(format!("target/source-{}", TAG));
    log_var!(source);
    let lib_dir = output.join(format!("lib-{}", TAG));
    log_var!(lib_dir);
    if lib_dir.exists() {
        log!("Directory {:?} already exists", lib_dir);
    } else {
        log!("Creating directory {:?}", lib_dir);
        fs::create_dir(lib_dir.clone()).unwrap();
    }
    let library_path = lib_dir.join(format!("lib{}.so", LIBRARY));
    log_var!(library_path);
    if library_path.exists() {
        log!("{:?} already exists, not building", library_path);
    } else {
        if let Err(e) = check_bazel() {
            println!("cargo:error=Bazel must be installed at version {} or greater. (Error: {})",
                     MIN_BAZEL,
                     e);
            process::exit(1);
        }
        let target_path = &TARGET.replace(":", "/");
        log_var!(target_path);
        if !Path::new(&source.join(".git")).exists() {
            run("git", |command| {
                command.arg("clone")
                    .arg(format!("--branch={}", TAG))
                    .arg("--recursive")
                    .arg(REPOSITORY)
                    .arg(&source)
            });
        }
        // Only configure if not previously configured.  Configuring runs a
        // `bazel clean`, which we don't want, because we want to be able to
        // continue from a cancelled build.
        let configure_hint_file_pb = source.join(".rust-configured");
        let configure_hint_file = Path::new(&configure_hint_file_pb);
        if !configure_hint_file.exists() {
            run("bash",
                |command| command.current_dir(&source)
                .env("TF_NEED_CUDA", if cfg!(feature = "tensorflow_gpu") {"1"} else {"0"})
                .arg("-c")
                .arg("yes ''|./configure"));
            File::create(configure_hint_file).unwrap();
        }
        run("bazel", |command| {
            command.current_dir(&source)
                .arg("build")
                .arg(format!("--jobs={}", get!("NUM_JOBS")))
                .arg("--compilation_mode=opt")
                .arg("--copt=-march=native")
                .arg(TARGET)
        });
        let target_bazel_bin = source.join("bazel-bin").join(target_path);
        log!("Copying {:?} to {:?}", target_bazel_bin, library_path);
        fs::copy(target_bazel_bin, library_path).unwrap();
    }

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", lib_dir.display());
}

fn run<F>(name: &str, mut configure: F)
    where F: FnMut(&mut Command) -> &mut Command
{
    let mut command = Command::new(name);
    let configured = configure(&mut command);
    log!("Executing {:?}", configured);
    if !ok!(configured.status()).success() {
        panic!("failed to execute {:?}", configured);
    }
    log!("Command {:?} finished successfully", configured);
}

// Building TF 0.11.0rc1 with Bazel 0.3.0 gives this error when running `configure`:
//   expected ConfigurationTransition or NoneType for 'cfg' while calling label_list but got
// string instead:     data.
//       ERROR: com.google.devtools.build.lib.packages.BuildFileContainsErrorsException: error
// loading package '': Extension file 'tensorflow/tensorflow.bzl' has errors.
// And the simple solution is to require Bazel 0.3.1 or higher.
fn check_bazel() -> Result<(), Box<Error>> {
    let mut command = Command::new("bazel");
    command.arg("version");
    log!("Executing {:?}", command);
    let out = try!(command.output());
    log!("Command {:?} finished successfully", command);
    let stdout = try!(String::from_utf8(out.stdout));
    let mut found_version = false;
    for line in stdout.lines() {
        if line.starts_with("Build label:") {
            found_version = true;
            let mut version_str = line.split(":")
                .nth(1)
                .unwrap()
                .split(" ")
                .nth(1)
                .unwrap()
                .trim();
            if version_str.ends_with('-') {
                // hyphen is 1 byte long, so it's safe
                version_str = &version_str[..version_str.len() - 1];
            }
            let version = try!(Version::parse(version_str));
            let want = try!(Version::parse(MIN_BAZEL));
            if version < want {
                return Err(format!("Installed version {} is less than required version {}",
                                   version_str,
                                   MIN_BAZEL)
                    .into());
            }
        }
    }
    if !found_version {
        return Err("Did not find version number in `bazel version` output.".into());
    }
    Ok(())
}
<commit_msg>Add TF_RUST_DOWNLOAD_DIR environment variable<commit_after>extern crate curl;
extern crate flate2;
extern crate pkg_config;
extern crate semver;
extern crate tar;

use std::error::Error;
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use std::{env, fs};

use curl::easy::Easy;
use flate2::read::GzDecoder;
use semver::Version;
use tar::Archive;

const LIBRARY: &'static str = "tensorflow";
const REPOSITORY: &'static str = "https://github.com/tensorflow/tensorflow.git";
const TARGET: &'static str = "tensorflow:libtensorflow.so";
// `VERSION` and `TAG` are separate because the tag is not always `'v' + VERSION`.
const VERSION: &'static str = "1.0.0";
const TAG: &'static str = "v1.0.0";
const MIN_BAZEL: &'static str = "0.3.2";

macro_rules! get(($name:expr) => (ok!(env::var($name))));
macro_rules! ok(($expression:expr) => ($expression.unwrap()));
macro_rules! log {
    ($fmt:expr) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt), line!()));
    ($fmt:expr, $($arg:tt)*) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt),
    line!(), $($arg)*));
}
macro_rules! log_var(($var:ident) => (log!(concat!(stringify!($var), " = {:?}"), $var)));

fn main() {
    if pkg_config::find_library(LIBRARY).is_ok() {
        log!("Returning early because {} was already found", LIBRARY);
        return;
    }

    let force_src = match env::var("TF_RUST_BUILD_FROM_SRC") {
        Ok(s) => s == "true",
        Err(_) => false,
    };
    if !force_src && env::consts::ARCH == "x86_64" && (env::consts::OS == "linux" || env::consts::OS == "macos") {
        install_prebuilt();
    } else {
        build_from_src();
    }
}

fn remove_suffix(value: &mut String, suffix: &str) {
    if value.ends_with(suffix) {
        let n = value.len();
        value.truncate(n - suffix.len());
    }
}

fn extract<P: AsRef<Path>, P2: AsRef<Path>>(archive_path: P, extract_to: P2) {
    let file = File::open(archive_path).unwrap();
    let unzipped = GzDecoder::new(file).unwrap();
    let mut a = Archive::new(unzipped);
    a.unpack(extract_to).unwrap();
}

// Downloads and unpacks a prebuilt binary. Only works for certain platforms.
fn install_prebuilt() {
    // Figure out the file names.
    let os = match env::consts::OS {
        "macos" => "darwin",
        x => x,
    };
    let proc_type = if cfg!(feature = "tensorflow_gpu") {"gpu"} else {"cpu"};
    let binary_url = format!(
        "https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-{}-{}-{}-{}.tar.gz",
        proc_type, os, env::consts::ARCH, VERSION);
    log_var!(binary_url);
    let short_file_name = binary_url.split("/").last().unwrap();
    let mut base_name = short_file_name.to_string();
    remove_suffix(&mut base_name, ".tar.gz");
    log_var!(base_name);
    let download_dir = match env::var("TF_RUST_DOWNLOAD_DIR") {
        Ok(s) => PathBuf::from(s),
        Err(_) => PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join("target"),
    };
    if !download_dir.exists() {
        fs::create_dir(&download_dir).unwrap();
    }
    let file_name = download_dir.join(short_file_name);
    log_var!(file_name);

    // Download the tarball.
    if !file_name.exists() {
        let f = File::create(&file_name).unwrap();
        let mut writer = BufWriter::new(f);
        let mut easy = Easy::new();
        easy.url(&binary_url).unwrap();
        easy.write_function(move |data| {
            Ok(writer.write(data).unwrap())
        }).unwrap();
        easy.perform().unwrap();

        let response_code = easy.response_code().unwrap();
        if response_code != 200 {
            panic!("Unexpected response code {} for {}", response_code, binary_url);
        }
    }

    // Extract the tarball.
    let unpacked_dir = download_dir.join(base_name);
    let lib_dir = unpacked_dir.join("lib");
    if !lib_dir.join(format!("lib{}.so", LIBRARY)).exists() {
        extract(file_name, &unpacked_dir);
    }

    //run("find", |command| command); // TODO: remove
    run("ls", |command| {
        command.arg("-l").arg(lib_dir.to_str().unwrap())
        }); // TODO: remove

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", lib_dir.display());
}

fn build_from_src() {
    let output = PathBuf::from(&get!("OUT_DIR"));
    log_var!(output);
    let source = PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join(format!("target/source-{}", TAG));
    log_var!(source);
    let lib_dir = output.join(format!("lib-{}", TAG));
    log_var!(lib_dir);
    if lib_dir.exists() {
        log!("Directory {:?} already exists", lib_dir);
    } else {
        log!("Creating directory {:?}", lib_dir);
        fs::create_dir(lib_dir.clone()).unwrap();
    }
    let library_path = lib_dir.join(format!("lib{}.so", LIBRARY));
    log_var!(library_path);
    if library_path.exists() {
        log!("{:?} already exists, not building", library_path);
    } else {
        if let Err(e) = check_bazel() {
            println!("cargo:error=Bazel must be installed at version {} or greater. (Error: {})",
                     MIN_BAZEL,
                     e);
            process::exit(1);
        }
        let target_path = &TARGET.replace(":", "/");
        log_var!(target_path);
        if !Path::new(&source.join(".git")).exists() {
            run("git", |command| {
                command.arg("clone")
                    .arg(format!("--branch={}", TAG))
                    .arg("--recursive")
                    .arg(REPOSITORY)
                    .arg(&source)
            });
        }
        // Only configure if not previously configured.  Configuring runs a
        // `bazel clean`, which we don't want, because we want to be able to
        // continue from a cancelled build.
        let configure_hint_file_pb = source.join(".rust-configured");
        let configure_hint_file = Path::new(&configure_hint_file_pb);
        if !configure_hint_file.exists() {
            run("bash",
                |command| command.current_dir(&source)
                .env("TF_NEED_CUDA", if cfg!(feature = "tensorflow_gpu") {"1"} else {"0"})
                .arg("-c")
                .arg("yes ''|./configure"));
            File::create(configure_hint_file).unwrap();
        }
        run("bazel", |command| {
            command.current_dir(&source)
                .arg("build")
                .arg(format!("--jobs={}", get!("NUM_JOBS")))
                .arg("--compilation_mode=opt")
                .arg("--copt=-march=native")
                .arg(TARGET)
        });
        let target_bazel_bin = source.join("bazel-bin").join(target_path);
        log!("Copying {:?} to {:?}", target_bazel_bin, library_path);
        fs::copy(target_bazel_bin, library_path).unwrap();
    }

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", lib_dir.display());
}

fn run<F>(name: &str, mut configure: F)
    where F: FnMut(&mut Command) -> &mut Command
{
    let mut command = Command::new(name);
    let configured = configure(&mut command);
    log!("Executing {:?}", configured);
    if !ok!(configured.status()).success() {
        panic!("failed to execute {:?}", configured);
    }
    log!("Command {:?} finished successfully", configured);
}

// Building TF 0.11.0rc1 with Bazel 0.3.0 gives this error when running `configure`:
//   expected ConfigurationTransition or NoneType for 'cfg' while calling label_list but got
// string instead:     data.
//       ERROR: com.google.devtools.build.lib.packages.BuildFileContainsErrorsException: error
// loading package '': Extension file 'tensorflow/tensorflow.bzl' has errors.
// And the simple solution is to require Bazel 0.3.1 or higher.
fn check_bazel() -> Result<(), Box<Error>> {
    let mut command = Command::new("bazel");
    command.arg("version");
    log!("Executing {:?}", command);
    let out = try!(command.output());
    log!("Command {:?} finished successfully", command);
    let stdout = try!(String::from_utf8(out.stdout));
    let mut found_version = false;
    for line in stdout.lines() {
        if line.starts_with("Build label:") {
            found_version = true;
            let mut version_str = line.split(":")
                .nth(1)
                .unwrap()
                .split(" ")
                .nth(1)
                .unwrap()
                .trim();
            if version_str.ends_with('-') {
                // hyphen is 1 byte long, so it's safe
                version_str = &version_str[..version_str.len() - 1];
            }
            let version = try!(Version::parse(version_str));
            let want = try!(Version::parse(MIN_BAZEL));
            if version < want {
                return Err(format!("Installed version {} is less than required version {}",
                                   version_str,
                                   MIN_BAZEL)
                    .into());
            }
        }
    }
    if !found_version {
        return Err("Did not find version number in `bazel version` output.".into());
    }
    Ok(())
}
<|endoftext|>


<commit_before>use crate::ffi;
use std::marker::PhantomData;
use std::os::raw::{c_char, c_int};
use std::ptr::NonNull;

/// A string we own that's allocated on the SQLite heap. Automatically calls
/// `sqlite3_free` when dropped, unless `into_raw` (or `into_inner`) is called
/// on it. If constructed from a rust string, `sqlite3_malloc` is used.
///
/// It has identical representation to a nonnull `*mut c_char`, so you can use
/// it transparently as one. It's nonnull, so Option<SqliteMallocString> is a
/// nullable one.
///
/// Note that this is for Strings we manage that are owned by SQLite, like
/// `sqlite3_extended_sql` results, some error message pointers. Most strings
/// are not this! Misuse is extremely dangerous!
///
/// Note that this is not a lossless interface. Incoming strings with internal
/// NULs are modified, and outgoing strings which are non-UTF8 are modified.
/// This seems unavoidable.
#[repr(transparent)]
pub(crate) struct SqliteMallocString {
    ptr: NonNull<c_char>,
    _boo: PhantomData<Box<[c_char]>>,
}
// This is owned data for a primitive type, and thus it's safe to implement
// these. That said, nothing needs them, and they make things easier to misuse.

// unsafe impl Send for SqliteMallocString {}
// unsafe impl Sync for SqliteMallocString {}

impl SqliteMallocString {
    /// SAFETY: Caller must be certain that `m` a nul-terminated c string
    /// allocated by sqlite3_malloc, and that SQLite expects us to free it!
    #[inline]
    pub(crate) unsafe fn from_raw_nonnull(ptr: NonNull<c_char>) -> Self {
        Self {
            ptr,
            _boo: PhantomData,
        }
    }

    /// SAFETY: Caller must be certain that `m` a nul-terminated c string
    /// allocated by sqlite3_malloc, and that SQLite expects us to free it!
    #[inline]
    pub(crate) unsafe fn from_raw(ptr: *mut c_char) -> Option<Self> {
        NonNull::new(ptr).map(|p| Self::from_raw_nonnull(p))
    }

    /// Get the pointer behind `self`. After this is called, we no longer manage
    /// it.
    #[inline]
    pub(crate) fn into_inner(self) -> NonNull<c_char> {
        let p = self.ptr;
        std::mem::forget(self);
        p
    }

    /// Get the pointer behind `self`. After this is called, we no longer manage
    /// it.
    #[inline]
    pub(crate) fn into_raw(self) -> *mut c_char {
        self.into_inner().as_ptr()
    }

    /// Borrow the pointer behind `self`. We still manage it when this function
    /// returns. If you want to relinquish ownership, use `into_raw`.
    #[inline]
    pub(crate) fn as_ptr(&self) -> *const c_char {
        self.ptr.as_ptr()
    }

    #[inline]
    pub(crate) fn as_cstr(&self) -> &std::ffi::CStr {
        unsafe { std::ffi::CStr::from_ptr(self.as_ptr()) }
    }

    #[inline]
    pub(crate) fn to_string_lossy(&self) -> std::borrow::Cow<'_, str> {
        self.as_cstr().to_string_lossy()
    }

    /// Convert `s` into a SQLite string.
    ///
    /// This should almost never be done except for cases like error messages or
    /// other strings that SQLite frees.
    ///
    /// If `s` contains internal NULs, we'll replace them with
    /// `NUL_REPLACE_CHAR`.
    ///
    /// Except for debug_asserts which may trigger during testing, this function
    /// never panics. If we hit integer overflow or the allocation fails, we
    /// call `handle_alloc_error` which aborts the program after calling a
    /// global hook.
    ///
    /// This means it's safe to use in extern "C" functions outside of
    /// catch_unwind.
    pub(crate) fn from_str(s: &str) -> Self {
        use std::convert::TryFrom;
        let s = if s.as_bytes().contains(&0) {
            std::borrow::Cow::Owned(make_nonnull(s))
        } else {
            std::borrow::Cow::Borrowed(s)
        };
        debug_assert!(!s.as_bytes().contains(&0));
        let bytes: &[u8] = s.as_ref().as_bytes();
        let src_ptr: *const c_char = bytes.as_ptr().cast();
        let src_len = bytes.len();
        let maybe_len_plus_1 = s.len().checked_add(1).and_then(|v| c_int::try_from(v).ok());
        unsafe {
            let res_ptr = maybe_len_plus_1
                .and_then(|len_to_alloc| {
                    // `>` because we added 1.
                    debug_assert!(len_to_alloc > 0);
                    debug_assert_eq!((len_to_alloc - 1) as usize, src_len);
                    NonNull::new(ffi::sqlite3_malloc(len_to_alloc) as *mut c_char)
                })
                .unwrap_or_else(|| {
                    use std::alloc::{handle_alloc_error, Layout};
                    // Report via handle_alloc_error so that it can be handled with any
                    // other allocation errors and properly diagnosed.
                    //
                    // This is safe:
                    // - `align` is never 0
                    // - `align` is always a power of 2.
                    // - `size` needs no realignment because it's guaranteed to be
                    //   aligned (everything is aligned to 1)
                    // - `size` is also never zero, although this function doesn't actually require it now.
                    let layout = Layout::from_size_align_unchecked(s.len().saturating_add(1), 1);
                    // Note: This call does not return.
                    handle_alloc_error(layout);
                });
            let buf: *mut i8 = res_ptr.as_ptr();
            src_ptr.copy_to_nonoverlapping(buf, src_len);
            buf.add(src_len).write(0);
            debug_assert_eq!(std::ffi::CStr::from_ptr(res_ptr.as_ptr()).to_bytes(), bytes);
            Self::from_raw_nonnull(res_ptr)
        }
    }
}

const NUL_REPLACE: &str = "␀";

#[cold]
fn make_nonnull(v: &str) -> String {
    v.replace('\0', NUL_REPLACE)
}

impl Drop for SqliteMallocString {
    fn drop(&mut self) {
        unsafe { ffi::sqlite3_free(self.ptr.as_ptr().cast()) };
    }
}

impl std::fmt::Debug for SqliteMallocString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.to_string_lossy().fmt(f)
    }
}

impl std::fmt::Display for SqliteMallocString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.to_string_lossy().fmt(f)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_from_str() {
        let to_check = [
            ("", ""),
            ("\0", "␀"),
            ("␀", "␀"),
            ("\0bar", "␀bar"),
            ("foo\0bar", "foo␀bar"),
            ("foo\0", "foo␀"),
            ("a\0b\0c\0\0d", "a␀b␀c␀␀d"),
            ("foobar0123", "foobar0123"),
        ];

        for &(input, output) in &to_check {
            let s = SqliteMallocString::from_str(input);
            assert_eq!(s.to_string_lossy(), output);
            assert_eq!(s.as_cstr().to_str().unwrap(), output);
        }
    }

    // This will trigger an asan error if into_raw still freed the ptr.
    #[test]
    fn test_lossy() {
        let p = SqliteMallocString::from_str("abcd").into_raw();
        // Make invalid
        let s = unsafe {
            p.cast::<u8>().write(b'\xff');
            SqliteMallocString::from_raw(p).unwrap()
        };
        assert_eq!(s.to_string_lossy().as_ref(), "\u{FFFD}bcd");
    }

    // This will trigger an asan error if into_raw still freed the ptr.
    #[test]
    fn test_into_raw() {
        let mut v = vec![];
        for i in 0..1000 {
            v.push(SqliteMallocString::from_str(&i.to_string()).into_raw());
            v.push(SqliteMallocString::from_str(&format!("abc {} 😀", i)).into_raw());
        }
        unsafe {
            for (i, s) in v.chunks_mut(2).enumerate() {
                let s0 = std::mem::replace(&mut s[0], std::ptr::null_mut());
                let s1 = std::mem::replace(&mut s[1], std::ptr::null_mut());
                assert_eq!(
                    std::ffi::CStr::from_ptr(s0).to_str().unwrap(),
                    &i.to_string()
                );
                assert_eq!(
                    std::ffi::CStr::from_ptr(s1).to_str().unwrap(),
                    &format!("abc {} 😀", i)
                );
                let _ = SqliteMallocString::from_raw(s0).unwrap();
                let _ = SqliteMallocString::from_raw(s1).unwrap();
            }
        }
    }
}
<commit_msg>Make clippy behave slightly more reasonably<commit_after>// This is used when either vtab or modern-sqlite is on. Different methods are
// used in each feature. Avoid having to track this for each function. We will
// still warn for anything that's not used by either, though.
#![cfg_attr(
    not(all(feature = "vtab", feature = "modern-sqlite")),
    allow(dead_code)
)]
use crate::ffi;
use std::marker::PhantomData;
use std::os::raw::{c_char, c_int};
use std::ptr::NonNull;

/// A string we own that's allocated on the SQLite heap. Automatically calls
/// `sqlite3_free` when dropped, unless `into_raw` (or `into_inner`) is called
/// on it. If constructed from a rust string, `sqlite3_malloc` is used.
///
/// It has identical representation to a nonnull `*mut c_char`, so you can use
/// it transparently as one. It's nonnull, so Option<SqliteMallocString> can be
/// used for nullable ones (it's still just one pointer).
///
/// Most strings shouldn't use this! Only places where the string needs to be
/// freed with `sqlite3_free`. This includes `sqlite3_extended_sql` results,
/// some error message pointers... Note that misuse is extremely dangerous!
///
/// Note that this is *not* a lossless interface. Incoming strings with internal
/// NULs are modified, and outgoing strings which are non-UTF8 are modified.
/// This seems unavoidable -- it tries very hard to not panic.
#[repr(transparent)]
pub(crate) struct SqliteMallocString {
    ptr: NonNull<c_char>,
    _boo: PhantomData<Box<[c_char]>>,
}
// This is owned data for a primitive type, and thus it's safe to implement
// these. That said, nothing needs them, and they make things easier to misuse.

// unsafe impl Send for SqliteMallocString {}
// unsafe impl Sync for SqliteMallocString {}

impl SqliteMallocString {
    /// SAFETY: Caller must be certain that `m` a nul-terminated c string
    /// allocated by sqlite3_malloc, and that SQLite expects us to free it!
    #[inline]
    pub(crate) unsafe fn from_raw_nonnull(ptr: NonNull<c_char>) -> Self {
        Self {
            ptr,
            _boo: PhantomData,
        }
    }

    /// SAFETY: Caller must be certain that `m` a nul-terminated c string
    /// allocated by sqlite3_malloc, and that SQLite expects us to free it!
    #[inline]
    pub(crate) unsafe fn from_raw(ptr: *mut c_char) -> Option<Self> {
        NonNull::new(ptr).map(|p| Self::from_raw_nonnull(p))
    }

    /// Get the pointer behind `self`. After this is called, we no longer manage
    /// it.
    #[inline]
    pub(crate) fn into_inner(self) -> NonNull<c_char> {
        let p = self.ptr;
        std::mem::forget(self);
        p
    }

    /// Get the pointer behind `self`. After this is called, we no longer manage
    /// it.
    #[inline]
    pub(crate) fn into_raw(self) -> *mut c_char {
        self.into_inner().as_ptr()
    }

    /// Borrow the pointer behind `self`. We still manage it when this function
    /// returns. If you want to relinquish ownership, use `into_raw`.
    #[inline]
    pub(crate) fn as_ptr(&self) -> *const c_char {
        self.ptr.as_ptr()
    }

    #[inline]
    pub(crate) fn as_cstr(&self) -> &std::ffi::CStr {
        unsafe { std::ffi::CStr::from_ptr(self.as_ptr()) }
    }

    #[inline]
    pub(crate) fn to_string_lossy(&self) -> std::borrow::Cow<'_, str> {
        self.as_cstr().to_string_lossy()
    }

    /// Convert `s` into a SQLite string.
    ///
    /// This should almost never be done except for cases like error messages or
    /// other strings that SQLite frees.
    ///
    /// If `s` contains internal NULs, we'll replace them with
    /// `NUL_REPLACE_CHAR`.
    ///
    /// Except for debug_asserts which may trigger during testing, this function
    /// never panics. If we hit integer overflow or the allocation fails, we
    /// call `handle_alloc_error` which aborts the program after calling a
    /// global hook.
    ///
    /// This means it's safe to use in extern "C" functions even outside of
    /// catch_unwind.
    pub(crate) fn from_str(s: &str) -> Self {
        use std::convert::TryFrom;
        let s = if s.as_bytes().contains(&0) {
            std::borrow::Cow::Owned(make_nonnull(s))
        } else {
            std::borrow::Cow::Borrowed(s)
        };
        debug_assert!(!s.as_bytes().contains(&0));
        let bytes: &[u8] = s.as_ref().as_bytes();
        let src_ptr: *const c_char = bytes.as_ptr().cast();
        let src_len = bytes.len();
        let maybe_len_plus_1 = s.len().checked_add(1).and_then(|v| c_int::try_from(v).ok());
        unsafe {
            let res_ptr = maybe_len_plus_1
                .and_then(|len_to_alloc| {
                    // `>` because we added 1.
                    debug_assert!(len_to_alloc > 0);
                    debug_assert_eq!((len_to_alloc - 1) as usize, src_len);
                    NonNull::new(ffi::sqlite3_malloc(len_to_alloc) as *mut c_char)
                })
                .unwrap_or_else(|| {
                    use std::alloc::{handle_alloc_error, Layout};
                    // Report via handle_alloc_error so that it can be handled with any
                    // other allocation errors and properly diagnosed.
                    //
                    // This is safe:
                    // - `align` is never 0
                    // - `align` is always a power of 2.
                    // - `size` needs no realignment because it's guaranteed to be
                    //   aligned (everything is aligned to 1)
                    // - `size` is also never zero, although this function doesn't actually require it now.
                    let layout = Layout::from_size_align_unchecked(s.len().saturating_add(1), 1);
                    // Note: This call does not return.
                    handle_alloc_error(layout);
                });
            let buf: *mut i8 = res_ptr.as_ptr();
            src_ptr.copy_to_nonoverlapping(buf, src_len);
            buf.add(src_len).write(0);
            debug_assert_eq!(std::ffi::CStr::from_ptr(res_ptr.as_ptr()).to_bytes(), bytes);
            Self::from_raw_nonnull(res_ptr)
        }
    }
}

const NUL_REPLACE: &str = "␀";

#[cold]
fn make_nonnull(v: &str) -> String {
    v.replace('\0', NUL_REPLACE)
}

impl Drop for SqliteMallocString {
    fn drop(&mut self) {
        unsafe { ffi::sqlite3_free(self.ptr.as_ptr().cast()) };
    }
}

impl std::fmt::Debug for SqliteMallocString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.to_string_lossy().fmt(f)
    }
}

impl std::fmt::Display for SqliteMallocString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.to_string_lossy().fmt(f)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_from_str() {
        let to_check = [
            ("", ""),
            ("\0", "␀"),
            ("␀", "␀"),
            ("\0bar", "␀bar"),
            ("foo\0bar", "foo␀bar"),
            ("foo\0", "foo␀"),
            ("a\0b\0c\0\0d", "a␀b␀c␀␀d"),
            ("foobar0123", "foobar0123"),
        ];

        for &(input, output) in &to_check {
            let s = SqliteMallocString::from_str(input);
            assert_eq!(s.to_string_lossy(), output);
            assert_eq!(s.as_cstr().to_str().unwrap(), output);
        }
    }

    // This will trigger an asan error if into_raw still freed the ptr.
    #[test]
    fn test_lossy() {
        let p = SqliteMallocString::from_str("abcd").into_raw();
        // Make invalid
        let s = unsafe {
            p.cast::<u8>().write(b'\xff');
            SqliteMallocString::from_raw(p).unwrap()
        };
        assert_eq!(s.to_string_lossy().as_ref(), "\u{FFFD}bcd");
    }

    // This will trigger an asan error if into_raw still freed the ptr.
    #[test]
    fn test_into_raw() {
        let mut v = vec![];
        for i in 0..1000 {
            v.push(SqliteMallocString::from_str(&i.to_string()).into_raw());
            v.push(SqliteMallocString::from_str(&format!("abc {} 😀", i)).into_raw());
        }
        unsafe {
            for (i, s) in v.chunks_mut(2).enumerate() {
                let s0 = std::mem::replace(&mut s[0], std::ptr::null_mut());
                let s1 = std::mem::replace(&mut s[1], std::ptr::null_mut());
                assert_eq!(
                    std::ffi::CStr::from_ptr(s0).to_str().unwrap(),
                    &i.to_string()
                );
                assert_eq!(
                    std::ffi::CStr::from_ptr(s1).to_str().unwrap(),
                    &format!("abc {} 😀", i)
                );
                let _ = SqliteMallocString::from_raw(s0).unwrap();
                let _ = SqliteMallocString::from_raw(s1).unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>use elements::{MemoryType, TableType, GlobalType, Type};
use elements::{BlockType, ValueType};
use validation::Error;

#[derive(Default, Debug)]
pub struct ModuleContext {
	pub memories: Vec<MemoryType>,
	pub tables: Vec<TableType>,
	pub globals: Vec<GlobalType>,
	pub types: Vec<Type>,
	pub func_type_indexes: Vec<u32>,
}

impl ModuleContext {
	pub fn memories(&self) -> &[MemoryType] {
		&self.memories
	}

	pub fn tables(&self) -> &[TableType] {
		&self.tables
	}

	pub fn globals(&self) -> &[GlobalType] {
		&self.globals
	}

	pub fn types(&self) -> &[Type] {
		&self.types
	}

	pub fn func_type_indexes(&self) -> &[u32] {
		&self.func_type_indexes
	}

	pub fn require_memory(&self, idx: u32) -> Result<(), Error> {
		if self.memories().get(idx as usize).is_none() {
			return Err(Error(format!("Memory at index {} doesn't exists", idx)));
		}
		Ok(())
	}

	pub fn require_table(&self, idx: u32) -> Result<&TableType, Error> {
		let table = match self.tables().get(idx as usize) {
			Some(table) => table,
			None => {
				return Err(Error(format!("Table at index {} doesn't exists", idx)));
			}
		};

		Ok(table)
	}

	pub fn require_function(&self, idx: u32) -> Result<(&[ValueType], BlockType), Error> {
		let ty_idx = match self.func_type_indexes().get(idx as usize) {
			Some(ty_idx) => *ty_idx,
			None => {
				return Err(Error(
					format!("Function at index {} doesn't exists", idx),
				));
			}
		};
		self.require_function_type(ty_idx)
	}

	pub fn require_function_type(&self, idx: u32) -> Result<(&[ValueType], BlockType), Error> {
		let ty = match self.types().get(idx as usize) {
			Some(&Type::Function(ref func_ty)) => func_ty,
			None => {
				return Err(Error(
					format!("Type at index {} doesn't exists", idx),
				));
			}
		};

		let params = ty.params();
		let return_ty = ty.return_type()
			.map(BlockType::Value)
			.unwrap_or(BlockType::NoResult);
		Ok((params, return_ty))
	}

	pub fn require_global(
		&self,
		idx: u32,
		mutability: Option<bool>,
	) -> Result<&GlobalType, Error> {
		let global = match self.globals().get(idx as usize) {
			Some(global) => global,
			None => {
				return Err(Error(format!("Global at index {} doesn't exists", idx)));
			}
		};

		if let Some(expected_mutable) = mutability {
			if expected_mutable && !global.is_mutable() {
				return Err(Error(format!("Expected global {} to be mutable", idx)));
			}
			if !expected_mutable && global.is_mutable() {
				return Err(Error(format!("Expected global {} to be immutable", idx)));
			}
		}

		Ok(global)
	}
}
<commit_msg>ok_or_else fixes<commit_after>use elements::{MemoryType, TableType, GlobalType, Type};
use elements::{BlockType, ValueType};
use validation::Error;

#[derive(Default, Debug)]
pub struct ModuleContext {
	pub memories: Vec<MemoryType>,
	pub tables: Vec<TableType>,
	pub globals: Vec<GlobalType>,
	pub types: Vec<Type>,
	pub func_type_indexes: Vec<u32>,
}

impl ModuleContext {
	pub fn memories(&self) -> &[MemoryType] {
		&self.memories
	}

	pub fn tables(&self) -> &[TableType] {
		&self.tables
	}

	pub fn globals(&self) -> &[GlobalType] {
		&self.globals
	}

	pub fn types(&self) -> &[Type] {
		&self.types
	}

	pub fn func_type_indexes(&self) -> &[u32] {
		&self.func_type_indexes
	}

	pub fn require_memory(&self, idx: u32) -> Result<(), Error> {
		if self.memories().get(idx as usize).is_none() {
			return Err(Error(format!("Memory at index {} doesn't exists", idx)));
		}
		Ok(())
	}

	pub fn require_table(&self, idx: u32) -> Result<&TableType, Error> {
		self.tables()
			.get(idx as usize)
			.ok_or_else(|| Error(format!("Table at index {} doesn't exists", idx)))
	}

	pub fn require_function(&self, idx: u32) -> Result<(&[ValueType], BlockType), Error> {
		let ty_idx = self.func_type_indexes()
			.get(idx as usize)
			.ok_or_else(|| Error(format!("Function at index {} doesn't exists", idx)))?;
		self.require_function_type(*ty_idx)
	}

	pub fn require_function_type(&self, idx: u32) -> Result<(&[ValueType], BlockType), Error> {
		let &Type::Function(ref ty) = self.types()
			.get(idx as usize)
			.ok_or_else(|| Error(format!("Type at index {} doesn't exists", idx)))?;

		let params = ty.params();
		let return_ty = ty.return_type()
			.map(BlockType::Value)
			.unwrap_or(BlockType::NoResult);
		Ok((params, return_ty))
	}

	pub fn require_global(&self, idx: u32, mutability: Option<bool>) -> Result<&GlobalType, Error> {
		let global = self.globals()
			.get(idx as usize)
			.ok_or_else(|| Error(format!("Global at index {} doesn't exists", idx)))?;

		if let Some(expected_mutable) = mutability {
			if expected_mutable && !global.is_mutable() {
				return Err(Error(format!("Expected global {} to be mutable", idx)));
			}
			if !expected_mutable && global.is_mutable() {
				return Err(Error(format!("Expected global {} to be immutable", idx)));
			}
		}
		Ok(global)
	}
}
<|endoftext|>


<commit_before>#[macro_use] extern crate cookie_factory;
#[macro_use] extern crate nom;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

pub mod flags;
pub mod generation;
pub mod parsing;
pub mod types;
pub mod value;
<commit_msg>types: export types::* at crate's root<commit_after>#[macro_use] extern crate cookie_factory;
#[macro_use] extern crate nom;
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;

mod types;

pub use types::*;

pub mod flags;
pub mod generation;
pub mod parsing;
pub mod value;
<|endoftext|>