<commit_before>#[cfg(test)]
pub mod test_common;

pub mod distance;

mod partition;
mod bounds;

use self::bounds::*;
use self::distance::*;

pub trait KdtreePointTrait: Copy {
    fn dims(&self) -> &[f64];
}

pub struct Kdtree<KdtreePoint> {
    nodes: Vec<KdtreeNode<KdtreePoint>>,
}

impl<KdtreePoint: KdtreePointTrait> Kdtree<KdtreePoint> {
    pub fn new(mut points: &mut [KdtreePoint]) -> Kdtree<KdtreePoint> {
        if points.len() == 0 {
            panic!("empty vector point not allowed");
        }

        let rect = Bounds::new_from_points(points);

        let mut tree = Kdtree {
            nodes: vec![],
        };

        tree.build_tree(&mut points, &rect);

        tree
    }

    pub fn nearest_search(&self, node: &KdtreePoint) -> KdtreePoint
    {
        let mut nearest_neighbor = 0usize;
        let mut best_distance = squared_euclidean(node.dims(), &self.nodes[0].point.dims());
        self.nearest_search_impl(node, 0usize, &mut best_distance, &mut nearest_neighbor);

        self.nodes[nearest_neighbor].point
    }

    pub fn has_neighbor_in_range(&self, node: &KdtreePoint, range: f64) -> bool {
        let squared_range = range * range;

        squared_euclidean(&self.nearest_search(node).dims(), node.dims()) <= squared_range
    }

    fn nearest_search_impl(&self, p: &KdtreePoint, searched_index: usize, best_distance_squared: &mut f64, best_leaf_found: &mut usize) {
        let node = &self.nodes[searched_index];

        let splitting_value = node.split_on;
        let point_splitting_dim_value = p.dims()[node.dimension];

        let (closer_node, farther_node) = self.select_closer_farther_node(node, splitting_value, point_splitting_dim_value);

        if let Some(closer_node) = closer_node {
            self.nearest_search_impl(p, closer_node, best_distance_squared, best_leaf_found);
        }

        let distance = squared_euclidean(p.dims(), node.point.dims());
        if distance < *best_distance_squared {
            *best_distance_squared = distance;
            *best_leaf_found = searched_index;
        }

        if let Some(farther_node) = farther_node {
            let distance_on_single_dimension = squared_euclidean(&[splitting_value], &[point_splitting_dim_value]);

            if distance_on_single_dimension <= *best_distance_squared {
                self.nearest_search_impl(p, farther_node, best_distance_squared, best_leaf_found);
            }
        }
    }

    fn select_closer_farther_node(&self, parent : &KdtreeNode<KdtreePoint>, parent_splits_dimension_on : f64, node_value_on_dimension : f64) -> (Option<usize>,Option<usize>) {
        if node_value_on_dimension <= parent_splits_dimension_on {
            (parent.left_node, parent.right_node)
        } else {
            (parent.right_node, parent.left_node)
        }
    }

    fn add_node(&mut self, p: KdtreePoint, dimension: usize, split_on: f64) -> usize {
        let node = KdtreeNode::new(p, dimension, split_on);

        self.nodes.push(node);
        self.nodes.len() - 1
    }

    fn build_tree(&mut self, nodes: &mut [KdtreePoint], bounds: &Bounds) -> usize {
        let (splitting_index, pivot_value) = partition::partition_sliding_midpoint(nodes, bounds.get_midvalue_of_widest_dim(), bounds.get_widest_dim());

        let node_id = self.add_node(nodes[splitting_index], bounds.get_widest_dim(), bounds.get_midvalue_of_widest_dim());
        let nodes_len = nodes.len();

        if splitting_index > 0 {
            let left_rect = bounds.clone_moving_max(pivot_value, bounds.get_widest_dim());
            let left_child_id = self.build_tree(&mut nodes[0..splitting_index], &left_rect);
            self.nodes[node_id].left_node = Some(left_child_id);
        }

        if splitting_index < nodes.len() - 1 {
            let right_rect = bounds.clone_moving_min(pivot_value, bounds.get_widest_dim());

            let right_child_id = self.build_tree(&mut nodes[splitting_index + 1..nodes_len], &right_rect);
            self.nodes[node_id].right_node = Some(right_child_id);
        }

        node_id
    }
}

pub struct KdtreeNode<T> {
    left_node: Option<usize>,
    right_node: Option<usize>,

    point: T,
    dimension: usize,
    split_on: f64
}

impl<T: KdtreePointTrait> KdtreeNode<T> {
    fn new(p: T, splitting_dimension: usize, split_on_value: f64) -> KdtreeNode<T> {
        KdtreeNode {
            left_node: None,
            right_node: None,

            point: p,
            dimension: splitting_dimension,
            split_on: split_on_value
        }
    }
}

#[cfg(test)]
mod tests {
    use ::kdtree::test_common::tests_utils::Point2WithId;

    use super::*;

    #[test]
    #[should_panic(expected = "empty vector point not allowed")]
    fn should_panic_given_empty_vector() {
        let mut empty_vec: Vec<Point2WithId> = vec![];

        Kdtree::new(&mut empty_vec);
    }

    quickcheck! {
        fn tree_build_creates_tree_with_as_many_leafs_as_there_is_points(xs : Vec<f64>) -> bool {
            if xs.len() == 0 {
                return true;
            }
            let mut vec : Vec<Point2WithId> = vec![];
            for i in 0 .. xs.len() {
                let p = Point2WithId::new(i as i32, xs[i], xs[i]);

                vec.push(p);
            }

            let tree = Kdtree::new(&mut qc_value_vec_to_2d_points_vec(&xs));

            let mut to_iterate : Vec<usize> = vec![];
            to_iterate.push(0);

            while to_iterate.len() > 0 {
                let last_index = to_iterate.last().unwrap().clone();
                let ref x = tree.nodes.get(last_index).unwrap();
                to_iterate.pop();
                if x.left_node.is_some() {
                    to_iterate.push(x.left_node.unwrap());
                }
                if x.right_node.is_some() {
                    to_iterate.push(x.right_node.unwrap());
                }
            }
            xs.len() == tree.nodes.len()
        }
    }

    quickcheck! {
        fn nearest_neighbor_search_using_qc(xs : Vec<f64>) -> bool {
            if xs.len() == 0 {
                return true;
            }

            let point_vec = qc_value_vec_to_2d_points_vec(&xs);
            let tree = Kdtree::new(&mut point_vec.clone());

            for p in &point_vec {
                let found_nn = tree.nearest_search(p);

                assert_eq!(p.id,found_nn.id);
            }

            true
        }
    }

    #[test]
    fn has_neighbor_in_range() {
        let mut vec: Vec<Point2WithId> = vec![Point2WithId::new(0,2.,0.)];

        let tree = Kdtree::new(&mut vec);

        assert_eq!(false,tree.has_neighbor_in_range(&Point2WithId::new(0,0.,0.), 0.));
        assert_eq!(false,tree.has_neighbor_in_range(&Point2WithId::new(0,0.,0.), 1.));
        assert_eq!(true,tree.has_neighbor_in_range(&Point2WithId::new(0,0.,0.), 2.));
        assert_eq!(true,tree.has_neighbor_in_range(&Point2WithId::new(0,0.,0.), 300.));
    }

    fn qc_value_vec_to_2d_points_vec(xs: &Vec<f64>) -> Vec<Point2WithId> {
        let mut vec: Vec<Point2WithId> = vec![];
        for i in 0..xs.len() {
            let mut is_duplicated_value = false;
            for j in 0..i {
                if xs[i] == xs[j] {
                    is_duplicated_value = true;
                    break;
                }
            }
            if !is_duplicated_value {
                let p = Point2WithId::new(i as i32, xs[i], xs[i]);
                vec.push(p);
            }
        }

        vec
    }
}<commit_msg>Working on add tree, fixed an issue on build tree where it did not build using sliding midpoint value<commit_after>#[cfg(test)]
pub mod test_common;

pub mod distance;

mod partition;
mod bounds;

use self::bounds::*;
use self::distance::*;

pub trait KdtreePointTrait: Copy {
    fn dims(&self) -> &[f64];
}

pub struct Kdtree<KdtreePoint> {
    nodes: Vec<KdtreeNode<KdtreePoint>>,
}

impl<KdtreePoint: KdtreePointTrait> Kdtree<KdtreePoint> {
    pub fn new(mut points: &mut [KdtreePoint]) -> Kdtree<KdtreePoint> {
        if points.len() == 0 {
            panic!("empty vector point not allowed");
        }

        let rect = Bounds::new_from_points(points);

        let mut tree = Kdtree {
            nodes: vec![],
        };

        tree.build_tree(&mut points, &rect);

        tree
    }

    pub fn nearest_search(&self, node: &KdtreePoint) -> KdtreePoint
    {
        let mut nearest_neighbor = 0usize;
        let mut best_distance = squared_euclidean(node.dims(), &self.nodes[0].point.dims());
        self.nearest_search_impl(node, 0usize, &mut best_distance, &mut nearest_neighbor);

        self.nodes[nearest_neighbor].point
    }

    pub fn has_neighbor_in_range(&self, node: &KdtreePoint, range: f64) -> bool {
        let squared_range = range * range;

        squared_euclidean(&self.nearest_search(node).dims(), node.dims()) <= squared_range
    }

    pub fn insert_node(&mut self, node_to_add : &KdtreePoint) {

        let current_index = 0;
        loop {
            let current_node = &self.nodes[current_index];
            if node_to_add.dims()[current_node.dimension] <= current_node.split_on {
            } else {

            }

            break;
        }
    }

    fn nearest_search_impl(&self, p: &KdtreePoint, searched_index: usize, best_distance_squared: &mut f64, best_leaf_found: &mut usize) {
        let node = &self.nodes[searched_index];

        let splitting_value = node.split_on;
        let point_splitting_dim_value = p.dims()[node.dimension];

        let (closer_node, farther_node) = self.select_closer_farther_node(node, splitting_value, point_splitting_dim_value);

        if let Some(closer_node) = closer_node {
            self.nearest_search_impl(p, closer_node, best_distance_squared, best_leaf_found);
        }

        let distance = squared_euclidean(p.dims(), node.point.dims());
        if distance < *best_distance_squared {
            *best_distance_squared = distance;
            *best_leaf_found = searched_index;
        }

        if let Some(farther_node) = farther_node {
            let distance_on_single_dimension = squared_euclidean(&[splitting_value], &[point_splitting_dim_value]);

            if distance_on_single_dimension <= *best_distance_squared {
                self.nearest_search_impl(p, farther_node, best_distance_squared, best_leaf_found);
            }
        }
    }

    fn select_closer_farther_node(&self, parent : &KdtreeNode<KdtreePoint>, parent_splits_dimension_on : f64, node_value_on_dimension : f64) -> (Option<usize>,Option<usize>) {
        if node_value_on_dimension <= parent_splits_dimension_on {
            (parent.left_node, parent.right_node)
        } else {
            (parent.right_node, parent.left_node)
        }
    }

    fn add_node(&mut self, p: KdtreePoint, dimension: usize, split_on: f64) -> usize {
        let node = KdtreeNode::new(p, dimension, split_on);

        self.nodes.push(node);
        self.nodes.len() - 1
    }

    fn build_tree(&mut self, nodes: &mut [KdtreePoint], bounds: &Bounds) -> usize {
        let (splitting_index, pivot_value) = partition::partition_sliding_midpoint(nodes, bounds.get_midvalue_of_widest_dim(), bounds.get_widest_dim());

        let node_id = self.add_node(nodes[splitting_index], bounds.get_widest_dim(), pivot_value);
        let nodes_len = nodes.len();

        if splitting_index > 0 {
            let left_rect = bounds.clone_moving_max(pivot_value, bounds.get_widest_dim());
            let left_child_id = self.build_tree(&mut nodes[0..splitting_index], &left_rect);
            self.nodes[node_id].left_node = Some(left_child_id);
        }

        if splitting_index < nodes.len() - 1 {
            let right_rect = bounds.clone_moving_min(pivot_value, bounds.get_widest_dim());

            let right_child_id = self.build_tree(&mut nodes[splitting_index + 1..nodes_len], &right_rect);
            self.nodes[node_id].right_node = Some(right_child_id);
        }

        node_id
    }
}

pub struct KdtreeNode<T> {
    left_node: Option<usize>,
    right_node: Option<usize>,

    point: T,
    dimension: usize,
    split_on: f64
}

impl<T: KdtreePointTrait> KdtreeNode<T> {
    fn new(p: T, splitting_dimension: usize, split_on_value: f64) -> KdtreeNode<T> {
        KdtreeNode {
            left_node: None,
            right_node: None,

            point: p,
            dimension: splitting_dimension,
            split_on: split_on_value
        }
    }
}

#[cfg(test)]
mod tests {
    use ::kdtree::test_common::tests_utils::Point2WithId;

    use super::*;

    #[test]
    #[should_panic(expected = "empty vector point not allowed")]
    fn should_panic_given_empty_vector() {
        let mut empty_vec: Vec<Point2WithId> = vec![];

        Kdtree::new(&mut empty_vec);
    }

    quickcheck! {
        fn tree_build_creates_tree_with_as_many_leafs_as_there_is_points(xs : Vec<f64>) -> bool {
            if xs.len() == 0 {
                return true;
            }
            let mut vec : Vec<Point2WithId> = vec![];
            for i in 0 .. xs.len() {
                let p = Point2WithId::new(i as i32, xs[i], xs[i]);

                vec.push(p);
            }

            let tree = Kdtree::new(&mut qc_value_vec_to_2d_points_vec(&xs));

            let mut to_iterate : Vec<usize> = vec![];
            to_iterate.push(0);

            while to_iterate.len() > 0 {
                let last_index = to_iterate.last().unwrap().clone();
                let ref x = tree.nodes.get(last_index).unwrap();
                to_iterate.pop();
                if x.left_node.is_some() {
                    to_iterate.push(x.left_node.unwrap());
                }
                if x.right_node.is_some() {
                    to_iterate.push(x.right_node.unwrap());
                }
            }
            xs.len() == tree.nodes.len()
        }
    }

    quickcheck! {
        fn nearest_neighbor_search_using_qc(xs : Vec<f64>) -> bool {
            if xs.len() == 0 {
                return true;
            }

            let point_vec = qc_value_vec_to_2d_points_vec(&xs);
            let tree = Kdtree::new(&mut point_vec.clone());

            for p in &point_vec {
                let found_nn = tree.nearest_search(p);

                assert_eq!(p.id,found_nn.id);
            }

            true
        }
    }

    #[test]
    fn has_neighbor_in_range() {
        let mut vec: Vec<Point2WithId> = vec![Point2WithId::new(0,2.,0.)];

        let tree = Kdtree::new(&mut vec);

        assert_eq!(false,tree.has_neighbor_in_range(&Point2WithId::new(0,0.,0.), 0.));
        assert_eq!(false,tree.has_neighbor_in_range(&Point2WithId::new(0,0.,0.), 1.));
        assert_eq!(true,tree.has_neighbor_in_range(&Point2WithId::new(0,0.,0.), 2.));
        assert_eq!(true,tree.has_neighbor_in_range(&Point2WithId::new(0,0.,0.), 300.));
    }

    #[test]
    fn incremental_add_adds_as_expected() {
        let mut vec = vec![Point2WithId::new(0,0.,0.)];

        let mut tree = Kdtree::new(&mut vec);

        tree.insert_node(&Point2WithId::new(0,1.,0.));
        tree.insert_node(&Point2WithId::new(0,-1.,0.));

        assert_eq!(tree.nodes.len(), 3);
    }

    fn qc_value_vec_to_2d_points_vec(xs: &Vec<f64>) -> Vec<Point2WithId> {
        let mut vec: Vec<Point2WithId> = vec![];
        for i in 0..xs.len() {
            let mut is_duplicated_value = false;
            for j in 0..i {
                if xs[i] == xs[j] {
                    is_duplicated_value = true;
                    break;
                }
            }
            if !is_duplicated_value {
                let p = Point2WithId::new(i as i32, xs[i], xs[i]);
                vec.push(p);
            }
        }

        vec
    }
}<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::{Error,Result};

use std::path::{Path,PathBuf};
use std::io::Write;
use std::process::Command;
use std::fs::{self, File,DirBuilder};
use uuid;
use std::ops::Drop;

/// Struct used to create zip (using filesystem and zip command)
pub struct Zipper {
    args: Vec<String>,
    path: PathBuf,
}

impl Zipper {
    /// creates new zipper
    ///
    /// path: the path to a temporary directory (zipper will create a random dir in it and clean it later)
    /// inner_dirs: a vec of inner directory to create in this directory
    pub fn new(path: &str) -> Result<Zipper> {
        let uuid = uuid::Uuid::new_v4();
        let zipper_path = Path::new(path).join(uuid.simple().to_string());

        try!(DirBuilder::new()
             .recursive(true)
             .create(&zipper_path)
             .map_err(|_| Error::zipper(format!("could not create temporary directory in {}", path))));

        Ok(Zipper {
            args: vec!(),
            path: zipper_path,
        })
    }

    /// writes a content to a temporary file
    pub fn write(&mut self, file: &str, content: &[u8], add_args: bool) -> Result<()> {
        let path = Path::new(file);
        if path.starts_with("..") || path.is_absolute() {
            return Err(Error::zipper(format!("file {} refers to an absolute or a parent path.
This is forbidden because we are supposed to create a temporary file in a temporary dir.", file)));
        }
        let dest_file = self.path.join(path);
        let dest_dir = dest_file.parent().unwrap();
        if !fs::metadata(dest_dir).is_ok() { // dir does not exist, create it
            try!(DirBuilder::new()
                 .recursive(true)
                 .create(&dest_dir)
                 .map_err(|_| Error::zipper(format!("could not create temporary directory in {}", dest_dir.display()))));
        }

        if let Ok(mut f) = File::create(&dest_file) {
            if f.write_all(content).is_ok() {
                if add_args {
                    self.args.push(String::from(file));
                }
                Ok(())
            } else {
                Err(Error::zipper(format!("could not write to temporary file {}", file)))
            }
        } else {
            Err(Error::zipper(format!("could not create temporary file {}", file)))
        }
    }

    /// Unzip a file and deletes it afterwards
    pub fn unzip(&mut self, file: &str) -> Result<()> {
        let output = Command::new("unzip")
            .current_dir(&self.path)
            .arg(file)
            .output()
            .map_err(|e| Error::zipper(format!("failed to execute unzip  on {}: {}", file, e)));

        try!(output);

        fs::remove_file(self.path.join(file))
            .map_err(|_| Error::zipper(format!("failed to remove file {}", file)))
    }

    /// run command and copy file name (supposed to result from the command) to current dir
    pub fn run_command(&mut self, mut command: Command, in_file: &str, out_file: &str) -> Result<String> {
        let res_output = command.args(&self.args)
            .current_dir(&self.path)
            .output()
            .map_err(|e| Error::zipper(format!("failed to execute process: {}", e)));
        let output = try!(res_output);
        try!(fs::copy(self.path.join(in_file), out_file).map_err(|_| {
            println!("{}", &String::from_utf8_lossy(&output.stdout));
            Error::zipper(format!("could not copy file {} to {}", in_file, out_file))
        }));
        Ok(String::from_utf8_lossy(&output.stdout).into_owned())
    }

    /// zip all files in zipper's tmp dir to a given file name and return odt file
    pub fn generate_odt(&mut self, command: &str, odt_file: &str) -> Result<String> {
        let mut command = Command::new(command);
        command.arg("-r");
        command.arg("result.odt");
        command.arg(".");
        self.run_command(command, "result.odt", odt_file)
    }

    /// generate a pdf file into given file name
    pub fn generate_pdf(&mut self, command: &str, tex_file: &str, pdf_file: &str) -> Result<String> {
        // first pass
        let _ = Command::new(command)
            .current_dir(&self.path)
            .arg(tex_file)
            .output();

        // second pass
        let mut command = Command::new(command);
        command.arg(tex_file);
        self.run_command(command, "result.pdf", pdf_file)
    }

    /// generate an epub into given file name
    pub fn generate_epub(&mut self, command: &str, file: &str) -> Result<String> {
        let mut command = Command::new(command);
        command.arg("-X");
        command.arg("result.epub");
        self.run_command(command, "result.epub", file)
    }
}

impl Drop for Zipper {
    fn drop(&mut self) {
        if let Err(err) = fs::remove_dir_all(&self.path) {
            println!("Error in zipper: could not delete temporary directory {}, error: {}", self.path.to_string_lossy(), err);
        }
    }
}
<commit_msg>Make zipper return an error if process didn't exit sucessfully<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::{Error,Result};

use std::path::{Path,PathBuf};
use std::io::Write;
use std::process::Command;
use std::fs::{self, File,DirBuilder};
use uuid;
use std::ops::Drop;

/// Struct used to create zip (using filesystem and zip command)
pub struct Zipper {
    args: Vec<String>,
    path: PathBuf,
}

impl Zipper {
    /// creates new zipper
    ///
    /// path: the path to a temporary directory (zipper will create a random dir in it and clean it later)
    /// inner_dirs: a vec of inner directory to create in this directory
    pub fn new(path: &str) -> Result<Zipper> {
        let uuid = uuid::Uuid::new_v4();
        let zipper_path = Path::new(path).join(uuid.simple().to_string());

        try!(DirBuilder::new()
             .recursive(true)
             .create(&zipper_path)
             .map_err(|_| Error::zipper(format!("could not create temporary directory in {}", path))));

        Ok(Zipper {
            args: vec!(),
            path: zipper_path,
        })
    }

    /// writes a content to a temporary file
    pub fn write(&mut self, file: &str, content: &[u8], add_args: bool) -> Result<()> {
        let path = Path::new(file);
        if path.starts_with("..") || path.is_absolute() {
            return Err(Error::zipper(format!("file {} refers to an absolute or a parent path.
This is forbidden because we are supposed to create a temporary file in a temporary dir.", file)));
        }
        let dest_file = self.path.join(path);
        let dest_dir = dest_file.parent().unwrap();
        if !fs::metadata(dest_dir).is_ok() { // dir does not exist, create it
            try!(DirBuilder::new()
                 .recursive(true)
                 .create(&dest_dir)
                 .map_err(|_| Error::zipper(format!("could not create temporary directory in {}", dest_dir.display()))));
        }

        if let Ok(mut f) = File::create(&dest_file) {
            if f.write_all(content).is_ok() {
                if add_args {
                    self.args.push(String::from(file));
                }
                Ok(())
            } else {
                Err(Error::zipper(format!("could not write to temporary file {}", file)))
            }
        } else {
            Err(Error::zipper(format!("could not create temporary file {}", file)))
        }
    }

    /// Unzip a file and deletes it afterwards
    pub fn unzip(&mut self, file: &str) -> Result<()> {
        let output = Command::new("unzip")
            .current_dir(&self.path)
            .arg(file)
            .output()
            .map_err(|e| Error::zipper(format!("failed to execute unzip  on {}: {}", file, e)));

        try!(output);

        fs::remove_file(self.path.join(file))
            .map_err(|_| Error::zipper(format!("failed to remove file {}", file)))
    }

    /// run command and copy file name (supposed to result from the command) to current dir
    pub fn run_command(&mut self, mut command: Command, in_file: &str, out_file: &str) -> Result<String> {
        let res_output = command.args(&self.args)
            .current_dir(&self.path)
            .output()
            .map_err(|e| Error::zipper(format!("failed to execute process: {}", e)));
        let output = try!(res_output);
        try!(fs::copy(self.path.join(in_file), out_file).map_err(|_| {
            println!("{}", &String::from_utf8_lossy(&output.stdout));
            Error::zipper(format!("could not copy file {} to {}", in_file, out_file))
        }));
        if output.status.success() {
            Ok(String::from_utf8_lossy(&output.stdout).into_owned())
        } else {
            Err(Error::zipper(format!("command didn't return succes:{}", String::from_utf8_lossy(&output.stdout))))
        }
    }

    /// zip all files in zipper's tmp dir to a given file name and return odt file
    pub fn generate_odt(&mut self, command: &str, odt_file: &str) -> Result<String> {
        let mut command = Command::new(command);
        command.arg("-r");
        command.arg("result.odt");
        command.arg(".");
        self.run_command(command, "result.odt", odt_file)
    }

    /// generate a pdf file into given file name
    pub fn generate_pdf(&mut self, command: &str, tex_file: &str, pdf_file: &str) -> Result<String> {
        // first pass
        let _ = Command::new(command)
            .current_dir(&self.path)
            .arg(tex_file)
            .output();

        // second pass
        let mut command = Command::new(command);
        command.arg(tex_file);
        self.run_command(command, "result.pdf", pdf_file)
    }

    /// generate an epub into given file name
    pub fn generate_epub(&mut self, command: &str, file: &str) -> Result<String> {
        let mut command = Command::new(command);
        command.arg("-X");
        command.arg("result.epub");
        self.run_command(command, "result.epub", file)
    }
}

impl Drop for Zipper {
    fn drop(&mut self) {
        if let Err(err) = fs::remove_dir_all(&self.path) {
            println!("Error in zipper: could not delete temporary directory {}, error: {}", self.path.to_string_lossy(), err);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::string::String;
use syntax::ast;
use syntax::ast::{Ident};
use syntax::codemap;
use syntax::codemap::{Spanned, Span, mk_sp, spanned, respan};
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, MacItem, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse;
use syntax::parse::{token, ParseSess};
use syntax::parse::token::Token;
use syntax::parse::parser::Parser;
use rustc::plugin::Registry;

struct Peg{
  name: Ident,
  rules: Vec<Rule>
}

struct Rule{
  name: Ident,
  def: Box<Expression>,
}

enum Expression_{
  StrLiteral(String), // "match me"
  AnySingleChar, // .
  NonTerminalSymbol(Ident), // another_rule
  Sequence(Vec<Box<Expression>>),
  Choice(Vec<Box<Expression>>)
}

type Expression = Spanned<Expression_>;

struct ParseError{
  span: Span,
  msg: String
}

struct PegParser<'a>
{
  rp: Parser<'a> // rust parser
}

impl<'a> PegParser<'a>
{
  fn new(sess: &'a ParseSess,
         cfg: ast::CrateConfig,
         tts: Vec<ast::TokenTree>) -> PegParser<'a>
  {
    PegParser{rp: parse::new_parser_from_tts(sess, cfg, tts)}
  }

  fn parse_grammar(&mut self) -> Peg
  {
    let grammar_name = self.parse_grammar_decl();
    let rules = self.parse_rules();
    Peg{name: grammar_name, rules: rules}
  }

  fn parse_grammar_decl(&mut self) -> Ident
  {
    if !self.eat_grammar_keyword() {
      let token_str = self.rp.this_token_to_str();
      self.rp.fatal(
        format!("expected the grammar declaration (of the form: `grammar <grammar-name>;`), found instead `{}`",
          token_str).as_slice())
    }
    let grammar_name = self.rp.parse_ident();
    self.rp.expect(&token::SEMI);
    grammar_name
  }

  fn eat_grammar_keyword(&mut self) -> bool
  {
    let is_grammar_kw = match self.rp.token {
      token::IDENT(sid, false) => "grammar" == id_to_string(sid).as_slice(),
      _ => false
    };
    if is_grammar_kw { self.rp.bump() }
    is_grammar_kw
  }

  fn parse_rules(&mut self) -> Vec<Rule>
  {
    let mut rules = vec![];
    while self.rp.token != token::EOF
    {
      rules.push(self.parse_rule());
    }
    rules
  }

  fn parse_rule(&mut self) -> Rule
  {
    let name = self.parse_rule_decl();
    self.rp.expect(&token::EQ);
    let body = self.parse_rule_rhs(id_to_string(name).as_slice());
    Rule{name: name, def: body}
  }

  fn parse_rule_decl(&mut self) -> Ident
  {
    self.rp.parse_ident()
  }

  fn parse_rule_rhs(&mut self, rule_name: &str) -> Box<Expression>
  {
    self.parse_rule_choice(rule_name)
  }

  fn parse_rule_choice(&mut self, rule_name: &str) -> Box<Expression>
  {
    let lo = self.rp.span.lo;
    let mut choices = Vec::new();
    loop{
      choices.push(self.parse_rule_seq(rule_name));
      let token = self.rp.token.clone();
      match token {
        token::BINOP(token::SLASH) => self.rp.bump(),
        _ => break
      }
    }
    let hi = self.rp.last_span.hi;
    box spanned(lo, hi, Choice(choices))
  }

  fn parse_rule_seq(&mut self, rule_name: &str) -> Box<Expression>
  {
    let lo = self.rp.span.lo;
    let mut seq = Vec::new();
    loop{
      match self.parse_rule_atom(rule_name){
        Some(expr) => seq.push(expr),
        None => break
      }
    }
    let hi = self.rp.last_span.hi;
    if seq.len() == 0 {
      self.rp.span_fatal(
        mk_sp(lo, hi),
        format!("In rule {}: must defined at least one parsing expression.", rule_name).as_slice());
    }
    box spanned(lo, hi, Sequence(seq))
  }

  fn last_respan<T>(&self, t: T) -> Box<Spanned<T>>
  {
    box respan(self.rp.last_span, t)
  }

  fn parse_rule_atom(&mut self, rule_name: &str) -> Option<Box<Expression>>
  {
    let token = self.rp.token.clone();
    match token {
      token::LIT_STR(id) => {
        self.rp.bump();
        Some(self.last_respan(StrLiteral(id_to_string(id))))
      },
      token::DOT => {
        self.rp.bump();
        Some(self.last_respan(AnySingleChar))
      },
      token::LPAREN => {
        self.rp.bump();
        let res = self.parse_rule_rhs(rule_name);
        self.rp.expect(&token::RPAREN);
        Some(res)
      },
      token::IDENT(id, _) => {
        if self.is_rule_lhs() { None }
        else {
          self.rp.bump();
          Some(self.last_respan(NonTerminalSymbol(id)))
        }
      },
      _ => { None }
    }
  }

  fn is_rule_lhs(&mut self) -> bool
  {
    self.rp.look_ahead(1, |t| match t { &token::EQ => true, _ => false})
  }
}

fn id_to_string(id: Ident) -> String
{
  String::from_str(token::get_ident(id).get())
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
  reg.register_macro("peg", expand)
}

fn expand(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
  parse(cx, tts)
}

fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Box<MacResult> {
  let mut parser = PegParser::new(cx.parse_sess(), cx.cfg(), Vec::from_slice(tts));
  let peg = parser.parse_grammar();

  check_peg(cx, &peg);
  compile_peg(cx, &peg)
}

struct ToTokensVec<T>
{
  v: Vec<T>
}

impl<T: ToTokens> ToTokens for ToTokensVec<T>
{
  fn to_tokens(&self, cx: &ExtCtxt) -> Vec<ast::TokenTree> {
    let mut tts = Vec::new();
    for e in self.v.iter() {
      tts = tts.append(e.to_tokens(cx).as_slice());
    }
    tts
  }
}

fn span_err(cx: &ExtCtxt, sp: Span, m: &str) {
  cx.parse_sess.span_diagnostic.span_err(sp, m);
}

fn check_peg(cx: &ExtCtxt, peg: &Peg)
{
  for rule in peg.rules.iter() {
    check_rule_rhs(cx, peg, &rule.def);
  }
}

fn check_rule_rhs(cx: &ExtCtxt, peg: &Peg, expr: &Box<Expression>)
{
  match &expr.node {
    &NonTerminalSymbol(id) => {
      check_non_terminal_symbol(cx, peg, id, expr.span)
    }
    &Sequence(ref seq) => {
      check_expr_slice(cx, peg, seq.as_slice())
    }
    &Choice(ref choices) => {
      check_expr_slice(cx, peg, choices.as_slice())
    }
    _ => ()
  }
}

fn check_non_terminal_symbol(cx: &ExtCtxt, peg: &Peg, id: Ident, sp: Span)
{
  check_if_rule_is_declared(cx, peg, id, sp)
}

fn check_if_rule_is_declared(cx: &ExtCtxt, peg: &Peg, id: Ident, sp: Span)
{
  for rule in peg.rules.iter() {
    if rule.name == id {
      return;
    }
  }
  span_err(cx, sp,
    format!("You try to call the rule `{}` which is not declared.", id_to_string(id)).as_slice());
}

fn check_expr_slice<'a>(cx: &ExtCtxt, peg: &Peg, seq: &'a [Box<Expression>])
{
  assert!(seq.len() > 0);
  for expr in seq.iter() {
    check_rule_rhs(cx, peg, expr);
  }
}

fn compile_peg(cx: &ExtCtxt, peg: &Peg) -> Box<MacResult>
{
  let grammar_name = peg.name;
  let parse_fn = compile_entry_point(cx, peg.rules.as_slice()[0].name);
  let mut rule_items = Vec::new();

  for rule in peg.rules.iter() {
    let rule_name = rule.name;
    let rule_def = compile_rule_rhs(cx, &rule.def);
    rule_items.push(quote_item!(cx,
      fn $rule_name (input: &str, pos: uint) -> Result<uint, String>
      {
        $rule_def
      }
    ).unwrap())
  }

  let items = ToTokensVec{v: rule_items};

  MacItem::new(quote_item!(cx,
    pub mod $grammar_name
    {
      $parse_fn
      $items
    }
  ).unwrap())
}

fn compile_entry_point(cx: &ExtCtxt, start_rule: Ident) -> ast::P<ast::Item>
{
  (quote_item!(cx,
    pub fn parse<'a>(input: &'a str) -> Result<Option<&'a str>, String>
    {
      match $start_rule(input, 0) {
        Ok(pos) => {
          assert!(pos <= input.len())
          if pos == input.len() {
            Ok(None)
          } else {
            Ok(Some(input.slice_from(pos)))
          }
        },
        Err(msg) => Err(msg)
      }
    })).unwrap()
}

fn compile_rule_rhs(cx: &ExtCtxt, expr: &Box<Expression>) -> ast::P<ast::Expr>
{
  match &expr.node {
    &StrLiteral(ref lit_str) => {
      compile_str_literal(cx, lit_str)
    },
    &AnySingleChar => {
      compile_any_single_char(cx)
    },
    &NonTerminalSymbol(id) => {
      compile_non_terminal_symbol(cx, id)
    },
    &Sequence(ref seq) => {
      compile_sequence(cx, seq.as_slice())
    },
    &Choice(ref choices) => {
      compile_choice(cx, choices.as_slice())
    }
  }
}

fn compile_non_terminal_symbol(cx: &ExtCtxt, id: Ident) -> ast::P<ast::Expr>
{
  quote_expr!(cx,
    $id(input, pos)
  )
}

fn compile_any_single_char(cx: &ExtCtxt) -> ast::P<ast::Expr>
{
  quote_expr!(cx,
    if input.len() - pos > 0 {
      Ok(pos + 1)
    } else {
      Err(format!("End of input when matching `.`"))
    }
  )
}

fn compile_str_literal(cx: &ExtCtxt, lit_str: &String) -> ast::P<ast::Expr>
{
  let s_len = lit_str.len();
  let lit_str_slice = lit_str.as_slice();
  quote_expr!(cx,
    if input.len() - pos == 0 {
      Err(format!("End of input when matching the literal `{}`", $lit_str_slice))
    } else if input.slice_from(pos).starts_with($lit_str_slice) {
      Ok(pos + $s_len)
    } else {
      Err(format!("Expected {} but got `{}`", $lit_str_slice, input.slice_from(pos)))
    }
  )
}

fn map_foldr_expr<'a>(cx: &ExtCtxt, seq: &'a [Box<Expression>],
  f: |ast::P<ast::Expr>, ast::P<ast::Expr>| -> ast::P<ast::Expr>) -> ast::P<ast::Expr>
{
  assert!(seq.len() > 0);
  seq.iter()
     .map(|e| { compile_rule_rhs(cx, e) })
     .rev()
     .reduce(f)
     .unwrap()
}

fn compile_sequence<'a>(cx: &ExtCtxt, seq: &'a [Box<Expression>]) -> ast::P<ast::Expr>
{
  map_foldr_expr(cx, seq, |tail, head| {
    quote_expr!(cx,
      match $head {
        Ok(pos) => {
          $tail
        }
        x => x
      }
    )
  })
}

fn compile_choice<'a>(cx: &ExtCtxt, choices: &'a [Box<Expression>]) -> ast::P<ast::Expr>
{
  map_foldr_expr(cx, choices, |tail, head| {
    quote_expr!(cx,
      match $head {
        Err(msg) => {
          $tail
        }
        x => x
      }
    )
  })
}<commit_msg>[Fix] Remove the support of reduce from rustc, it was not trivially implementable for the general case.<commit_after>// Copyright 2014 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::string::String;
use syntax::ast;
use syntax::ast::{Ident};
use syntax::codemap;
use syntax::codemap::{Spanned, Span, mk_sp, spanned, respan};
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, MacItem, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse;
use syntax::parse::{token, ParseSess};
use syntax::parse::token::Token;
use syntax::parse::parser::Parser;
use rustc::plugin::Registry;

struct Peg{
  name: Ident,
  rules: Vec<Rule>
}

struct Rule{
  name: Ident,
  def: Box<Expression>,
}

enum Expression_{
  StrLiteral(String), // "match me"
  AnySingleChar, // .
  NonTerminalSymbol(Ident), // another_rule
  Sequence(Vec<Box<Expression>>),
  Choice(Vec<Box<Expression>>)
}

type Expression = Spanned<Expression_>;

struct ParseError{
  span: Span,
  msg: String
}

struct PegParser<'a>
{
  rp: Parser<'a> // rust parser
}

impl<'a> PegParser<'a>
{
  fn new(sess: &'a ParseSess,
         cfg: ast::CrateConfig,
         tts: Vec<ast::TokenTree>) -> PegParser<'a>
  {
    PegParser{rp: parse::new_parser_from_tts(sess, cfg, tts)}
  }

  fn parse_grammar(&mut self) -> Peg
  {
    let grammar_name = self.parse_grammar_decl();
    let rules = self.parse_rules();
    Peg{name: grammar_name, rules: rules}
  }

  fn parse_grammar_decl(&mut self) -> Ident
  {
    if !self.eat_grammar_keyword() {
      let token_str = self.rp.this_token_to_str();
      self.rp.fatal(
        format!("expected the grammar declaration (of the form: `grammar <grammar-name>;`), found instead `{}`",
          token_str).as_slice())
    }
    let grammar_name = self.rp.parse_ident();
    self.rp.expect(&token::SEMI);
    grammar_name
  }

  fn eat_grammar_keyword(&mut self) -> bool
  {
    let is_grammar_kw = match self.rp.token {
      token::IDENT(sid, false) => "grammar" == id_to_string(sid).as_slice(),
      _ => false
    };
    if is_grammar_kw { self.rp.bump() }
    is_grammar_kw
  }

  fn parse_rules(&mut self) -> Vec<Rule>
  {
    let mut rules = vec![];
    while self.rp.token != token::EOF
    {
      rules.push(self.parse_rule());
    }
    rules
  }

  fn parse_rule(&mut self) -> Rule
  {
    let name = self.parse_rule_decl();
    self.rp.expect(&token::EQ);
    let body = self.parse_rule_rhs(id_to_string(name).as_slice());
    Rule{name: name, def: body}
  }

  fn parse_rule_decl(&mut self) -> Ident
  {
    self.rp.parse_ident()
  }

  fn parse_rule_rhs(&mut self, rule_name: &str) -> Box<Expression>
  {
    self.parse_rule_choice(rule_name)
  }

  fn parse_rule_choice(&mut self, rule_name: &str) -> Box<Expression>
  {
    let lo = self.rp.span.lo;
    let mut choices = Vec::new();
    loop{
      choices.push(self.parse_rule_seq(rule_name));
      let token = self.rp.token.clone();
      match token {
        token::BINOP(token::SLASH) => self.rp.bump(),
        _ => break
      }
    }
    let hi = self.rp.last_span.hi;
    box spanned(lo, hi, Choice(choices))
  }

  fn parse_rule_seq(&mut self, rule_name: &str) -> Box<Expression>
  {
    let lo = self.rp.span.lo;
    let mut seq = Vec::new();
    loop{
      match self.parse_rule_atom(rule_name){
        Some(expr) => seq.push(expr),
        None => break
      }
    }
    let hi = self.rp.last_span.hi;
    if seq.len() == 0 {
      self.rp.span_fatal(
        mk_sp(lo, hi),
        format!("In rule {}: must defined at least one parsing expression.", rule_name).as_slice());
    }
    box spanned(lo, hi, Sequence(seq))
  }

  fn last_respan<T>(&self, t: T) -> Box<Spanned<T>>
  {
    box respan(self.rp.last_span, t)
  }

  fn parse_rule_atom(&mut self, rule_name: &str) -> Option<Box<Expression>>
  {
    let token = self.rp.token.clone();
    match token {
      token::LIT_STR(id) => {
        self.rp.bump();
        Some(self.last_respan(StrLiteral(id_to_string(id))))
      },
      token::DOT => {
        self.rp.bump();
        Some(self.last_respan(AnySingleChar))
      },
      token::LPAREN => {
        self.rp.bump();
        let res = self.parse_rule_rhs(rule_name);
        self.rp.expect(&token::RPAREN);
        Some(res)
      },
      token::IDENT(id, _) => {
        if self.is_rule_lhs() { None }
        else {
          self.rp.bump();
          Some(self.last_respan(NonTerminalSymbol(id)))
        }
      },
      _ => { None }
    }
  }

  fn is_rule_lhs(&mut self) -> bool
  {
    self.rp.look_ahead(1, |t| match t { &token::EQ => true, _ => false})
  }
}

fn id_to_string(id: Ident) -> String
{
  String::from_str(token::get_ident(id).get())
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
  reg.register_macro("peg", expand)
}

fn expand(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
  parse(cx, tts)
}

fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Box<MacResult> {
  let mut parser = PegParser::new(cx.parse_sess(), cx.cfg(), Vec::from_slice(tts));
  let peg = parser.parse_grammar();

  check_peg(cx, &peg);
  compile_peg(cx, &peg)
}

struct ToTokensVec<T>
{
  v: Vec<T>
}

impl<T: ToTokens> ToTokens for ToTokensVec<T>
{
  fn to_tokens(&self, cx: &ExtCtxt) -> Vec<ast::TokenTree> {
    let mut tts = Vec::new();
    for e in self.v.iter() {
      tts = tts.append(e.to_tokens(cx).as_slice());
    }
    tts
  }
}

fn span_err(cx: &ExtCtxt, sp: Span, m: &str) {
  cx.parse_sess.span_diagnostic.span_err(sp, m);
}

fn check_peg(cx: &ExtCtxt, peg: &Peg)
{
  for rule in peg.rules.iter() {
    check_rule_rhs(cx, peg, &rule.def);
  }
}

fn check_rule_rhs(cx: &ExtCtxt, peg: &Peg, expr: &Box<Expression>)
{
  match &expr.node {
    &NonTerminalSymbol(id) => {
      check_non_terminal_symbol(cx, peg, id, expr.span)
    }
    &Sequence(ref seq) => {
      check_expr_slice(cx, peg, seq.as_slice())
    }
    &Choice(ref choices) => {
      check_expr_slice(cx, peg, choices.as_slice())
    }
    _ => ()
  }
}

fn check_non_terminal_symbol(cx: &ExtCtxt, peg: &Peg, id: Ident, sp: Span)
{
  check_if_rule_is_declared(cx, peg, id, sp)
}

fn check_if_rule_is_declared(cx: &ExtCtxt, peg: &Peg, id: Ident, sp: Span)
{
  for rule in peg.rules.iter() {
    if rule.name == id {
      return;
    }
  }
  span_err(cx, sp,
    format!("You try to call the rule `{}` which is not declared.", id_to_string(id)).as_slice());
}

fn check_expr_slice<'a>(cx: &ExtCtxt, peg: &Peg, seq: &'a [Box<Expression>])
{
  assert!(seq.len() > 0);
  for expr in seq.iter() {
    check_rule_rhs(cx, peg, expr);
  }
}

fn compile_peg(cx: &ExtCtxt, peg: &Peg) -> Box<MacResult>
{
  let grammar_name = peg.name;
  let parse_fn = compile_entry_point(cx, peg.rules.as_slice()[0].name);
  let mut rule_items = Vec::new();

  for rule in peg.rules.iter() {
    let rule_name = rule.name;
    let rule_def = compile_rule_rhs(cx, &rule.def);
    rule_items.push(quote_item!(cx,
      fn $rule_name (input: &str, pos: uint) -> Result<uint, String>
      {
        $rule_def
      }
    ).unwrap())
  }

  let items = ToTokensVec{v: rule_items};

  MacItem::new(quote_item!(cx,
    pub mod $grammar_name
    {
      $parse_fn
      $items
    }
  ).unwrap())
}

fn compile_entry_point(cx: &ExtCtxt, start_rule: Ident) -> ast::P<ast::Item>
{
  (quote_item!(cx,
    pub fn parse<'a>(input: &'a str) -> Result<Option<&'a str>, String>
    {
      match $start_rule(input, 0) {
        Ok(pos) => {
          assert!(pos <= input.len())
          if pos == input.len() {
            Ok(None)
          } else {
            Ok(Some(input.slice_from(pos)))
          }
        },
        Err(msg) => Err(msg)
      }
    })).unwrap()
}

fn compile_rule_rhs(cx: &ExtCtxt, expr: &Box<Expression>) -> ast::P<ast::Expr>
{
  match &expr.node {
    &StrLiteral(ref lit_str) => {
      compile_str_literal(cx, lit_str)
    },
    &AnySingleChar => {
      compile_any_single_char(cx)
    },
    &NonTerminalSymbol(id) => {
      compile_non_terminal_symbol(cx, id)
    },
    &Sequence(ref seq) => {
      compile_sequence(cx, seq.as_slice())
    },
    &Choice(ref choices) => {
      compile_choice(cx, choices.as_slice())
    }
  }
}

fn compile_non_terminal_symbol(cx: &ExtCtxt, id: Ident) -> ast::P<ast::Expr>
{
  quote_expr!(cx,
    $id(input, pos)
  )
}

fn compile_any_single_char(cx: &ExtCtxt) -> ast::P<ast::Expr>
{
  quote_expr!(cx,
    if input.len() - pos > 0 {
      Ok(pos + 1)
    } else {
      Err(format!("End of input when matching `.`"))
    }
  )
}

fn compile_str_literal(cx: &ExtCtxt, lit_str: &String) -> ast::P<ast::Expr>
{
  let s_len = lit_str.len();
  let lit_str_slice = lit_str.as_slice();
  quote_expr!(cx,
    if input.len() - pos == 0 {
      Err(format!("End of input when matching the literal `{}`", $lit_str_slice))
    } else if input.slice_from(pos).starts_with($lit_str_slice) {
      Ok(pos + $s_len)
    } else {
      Err(format!("Expected {} but got `{}`", $lit_str_slice, input.slice_from(pos)))
    }
  )
}

fn map_foldr_expr<'a>(cx: &ExtCtxt, seq: &'a [Box<Expression>],
  f: |ast::P<ast::Expr>, ast::P<ast::Expr>| -> ast::P<ast::Expr>) -> ast::P<ast::Expr>
{
  assert!(seq.len() > 0);
  let mut seq_it = seq
    .iter()
    .map(|e| { compile_rule_rhs(cx, e) })
    .rev();

  let head = seq_it.next().unwrap();
  seq_it.fold(head, f)
}

fn compile_sequence<'a>(cx: &ExtCtxt, seq: &'a [Box<Expression>]) -> ast::P<ast::Expr>
{
  map_foldr_expr(cx, seq, |tail, head| {
    quote_expr!(cx,
      match $head {
        Ok(pos) => {
          $tail
        }
        x => x
      }
    )
  })
}

fn compile_choice<'a>(cx: &ExtCtxt, choices: &'a [Box<Expression>]) -> ast::P<ast::Expr>
{
  map_foldr_expr(cx, choices, |tail, head| {
    quote_expr!(cx,
      match $head {
        Err(msg) => {
          $tail
        }
        x => x
      }
    )
  })
}<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers.
// Copyright 2015 Guillaume Gomez
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Library to interface with chunks of memory allocated in C.
//!
//! It is often desirable to safely interface with memory allocated from C,
//! encapsulating the unsafety into allocation and destruction time.  Indeed,
//! allocating memory externally is currently the only way to give Rust shared
//! mut state with C programs that keep their own references; vectors are
//! unsuitable because they could be reallocated or moved at any time, and
//! importing C memory into a vector takes a one-time snapshot of the memory.
//!
//! This module simplifies the usage of such external blocks of memory.  Memory
//! is encapsulated into an opaque object after creation; the lifecycle of the
//! memory can be optionally managed by Rust, if an appropriate destructor
//! closure is provided.  Safety is ensured by bounds-checking accesses, which
//! are marshalled through get and set functions.
//!
//! There are three unsafe functions: the two constructors, and the
//! unwrap method. The constructors are unsafe for the
//! obvious reason (they act on a pointer that cannot be checked inside the
//! method), but `unwrap()` is somewhat more subtle in its unsafety.
//! It returns the contained pointer, but at the same time destroys the CVec
//! without running its destructor. This can be used to pass memory back to
//! C, but care must be taken that the ownership of underlying resources are
//! handled correctly, i.e. that allocated memory is eventually freed
//! if necessary.

#![feature(unsafe_destructor, core, std_misc)]

use std::mem;
use std::ops::{Drop, FnOnce};
use std::option::Option;
use std::option::Option::{Some, None};
use std::ptr::PtrExt;
use std::ptr;
use std::raw;
use std::slice::AsSlice;
use std::thunk::{Thunk};

/// The type representing a foreign chunk of memory
pub struct CVec<T> {
    base: *mut T,
    len: usize,
    dtor: Option<Thunk>,
}

#[unsafe_destructor]
impl<T> Drop for CVec<T> {
    fn drop(&mut self) {
        match self.dtor.take() {
            None => (),
            Some(f) => f.invoke(())
        }
    }
}

impl<T> CVec<T> {
    /// Create a `CVec` from a raw pointer to a buffer with a given length.
    ///
    /// Panics if the given pointer is null. The returned vector will not attempt
    /// to deallocate the vector when dropped.
    ///
    /// # Arguments
    ///
    /// * base - A raw pointer to a buffer
    /// * len - The number of elements in the buffer
    pub unsafe fn new(base: *mut T, len: usize) -> CVec<T> {
        assert!(base != ptr::null_mut());
        CVec {
            base: base,
            len: len,
            dtor: None,
        }
    }

    /// Create a `CVec` from a foreign buffer, with a given length,
    /// and a function to run upon destruction.
    ///
    /// Panics if the given pointer is null.
    ///
    /// # Arguments
    ///
    /// * base - A foreign pointer to a buffer
    /// * len - The number of elements in the buffer
    /// * dtor - A fn to run when the value is destructed, useful
    ///          for freeing the buffer, etc.
    pub unsafe fn new_with_dtor<F>(base: *mut T,
                                   len: usize,
                                   dtor: F)
                                   -> CVec<T>
        where F : FnOnce(), F : Send
    {
        assert!(base != ptr::null_mut());
        let dtor: Thunk = Thunk::new(dtor);
        CVec {
            base: base,
            len: len,
            dtor: Some(dtor)
        }
    }

    /// View the stored data as a mutable slice.
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        unsafe {
            mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
        }
    }

    /// Retrieves an element at a given index, returning `None` if the requested
    /// index is greater than the length of the vector.
    pub fn get<'a>(&'a self, ofs: usize) -> Option<&'a T> {
        if ofs < self.len {
            Some(unsafe { &*self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Retrieves a mutable element at a given index, returning `None` if the
    /// requested index is greater than the length of the vector.
    pub fn get_mut<'a>(&'a mut self, ofs: usize) -> Option<&'a mut T> {
        if ofs < self.len {
            Some(unsafe { &mut *self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Unwrap the pointer without running the destructor
    ///
    /// This method retrieves the underlying pointer, and in the process
    /// destroys the CVec but without running the destructor. A use case
    /// would be transferring ownership of the buffer to a C function, as
    /// in this case you would not want to run the destructor.
    ///
    /// Note that if you want to access the underlying pointer without
    /// cancelling the destructor, you can simply call `transmute` on the return
    /// value of `get(0)`.
    pub unsafe fn into_inner(mut self) -> *mut T {
        self.dtor = None;
        self.base
    }

    /// Deprecated, use into_inner() instead
    #[deprecated = "renamed to into_inner()"]
    pub unsafe fn unwrap(self) -> *mut T { self.into_inner() }

    /// Returns the number of items in this vector.
    pub fn len(&self) -> usize { self.len }

    /// Returns whether this vector is empty.
    pub fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<T> AsSlice<T> for CVec<T> {
    /// View the stored data as a slice.
    fn as_slice<'a>(&'a self) -> &'a [T] {
        unsafe {
            mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
        }
    }
}

#[cfg(test)]
mod tests {
    use prelude::v1::*;

    use super::CVec;
    use libc;
    use ptr;

    fn malloc(n: uint) -> CVec<u8> {
        unsafe {
            let mem = ptr::Unique(libc::malloc(n as libc::size_t));
            if mem.0.is_null() { ::alloc::oom() }

            CVec::new_with_dtor(mem.0 as *mut u8,
                                n,
                                move|| { libc::free(mem.0 as *mut libc::c_void); })
        }
    }

    #[test]
    fn test_basic() {
        let mut cv = malloc(16);

        *cv.get_mut(3).unwrap() = 8;
        *cv.get_mut(4).unwrap() = 9;
        assert_eq!(*cv.get(3).unwrap(), 8);
        assert_eq!(*cv.get(4).unwrap(), 9);
        assert_eq!(cv.len(), 16);
    }

    #[test]
    #[should_fail]
    fn test_panic_at_null() {
        unsafe {
            CVec::new(ptr::null_mut::<u8>(), 9);
        }
    }

    #[test]
    fn test_overrun_get() {
        let cv = malloc(16);

        assert!(cv.get(17).is_none());
    }

    #[test]
    fn test_overrun_set() {
        let mut cv = malloc(16);

        assert!(cv.get_mut(17).is_none());
    }

    #[test]
    fn test_unwrap() {
        unsafe {
            let cv = CVec::new_with_dtor(1 as *mut int,
                                         0,
                                         move|&:| panic!("Don't run this destructor!"));
            let p = cv.into_inner();
            assert_eq!(p, 1 as *mut int);
        }
    }

}<commit_msg>Add lifetime parameters<commit_after>// Copyright 2012 The Rust Project Developers.
// Copyright 2015 Guillaume Gomez
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Library to interface with chunks of memory allocated in C.
//!
//! It is often desirable to safely interface with memory allocated from C,
//! encapsulating the unsafety into allocation and destruction time.  Indeed,
//! allocating memory externally is currently the only way to give Rust shared
//! mut state with C programs that keep their own references; vectors are
//! unsuitable because they could be reallocated or moved at any time, and
//! importing C memory into a vector takes a one-time snapshot of the memory.
//!
//! This module simplifies the usage of such external blocks of memory.  Memory
//! is encapsulated into an opaque object after creation; the lifecycle of the
//! memory can be optionally managed by Rust, if an appropriate destructor
//! closure is provided.  Safety is ensured by bounds-checking accesses, which
//! are marshalled through get and set functions.
//!
//! There are three unsafe functions: the two constructors, and the
//! unwrap method. The constructors are unsafe for the
//! obvious reason (they act on a pointer that cannot be checked inside the
//! method), but `unwrap()` is somewhat more subtle in its unsafety.
//! It returns the contained pointer, but at the same time destroys the CVec
//! without running its destructor. This can be used to pass memory back to
//! C, but care must be taken that the ownership of underlying resources are
//! handled correctly, i.e. that allocated memory is eventually freed
//! if necessary.

#![feature(unsafe_destructor, core, std_misc)]

use std::mem;
use std::ops::{Drop, FnOnce};
use std::option::Option;
use std::option::Option::{Some, None};
use std::ptr::PtrExt;
use std::ptr;
use std::raw;
use std::slice::AsSlice;
use std::thunk::{Thunk};

/// The type representing a foreign chunk of memory
pub struct CVec<'b, T> {
    base: *mut T,
    len: usize,
    dtor: Option<Thunk<'b>>
}

#[unsafe_destructor]
impl<'b, T> Drop for CVec<'b T> {
    fn drop(&mut self) {
        match self.dtor.take() {
            None => (),
            Some(f) => f.invoke(())
        }
    }
}

impl<'b, T> CVec<'b, T> {
    /// Create a `CVec` from a raw pointer to a buffer with a given length.
    ///
    /// Panics if the given pointer is null. The returned vector will not attempt
    /// to deallocate the vector when dropped.
    ///
    /// # Arguments
    ///
    /// * base - A raw pointer to a buffer
    /// * len - The number of elements in the buffer
    pub unsafe fn new(base: *mut T, len: usize) -> CVec<'b, T> {
        assert!(base != ptr::null_mut());
        CVec {
            base: base,
            len: len,
            dtor: None,
        }
    }

    /// Create a `CVec` from a foreign buffer, with a given length,
    /// and a function to run upon destruction.
    ///
    /// Panics if the given pointer is null.
    ///
    /// # Arguments
    ///
    /// * base - A foreign pointer to a buffer
    /// * len - The number of elements in the buffer
    /// * dtor - A fn to run when the value is destructed, useful
    ///          for freeing the buffer, etc.
    pub unsafe fn new_with_dtor<F>(base: *mut T,
                                   len: usize,
                                   dtor: F)
                                   -> CVec<'b, T>
        where F : FnOnce(), F : Send, F : 'b
    {
        assert!(base != ptr::null_mut());
        let dtor: Thunk = Thunk::new(dtor);
        CVec {
            base: base,
            len: len,
            dtor: Some(dtor)
        }
    }

    /// View the stored data as a mutable slice.
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        unsafe {
            mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
        }
    }

    /// Retrieves an element at a given index, returning `None` if the requested
    /// index is greater than the length of the vector.
    pub fn get<'a>(&'a self, ofs: usize) -> Option<&'a T> {
        if ofs < self.len {
            Some(unsafe { &*self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Retrieves a mutable element at a given index, returning `None` if the
    /// requested index is greater than the length of the vector.
    pub fn get_mut<'a>(&'a mut self, ofs: usize) -> Option<&'a mut T> {
        if ofs < self.len {
            Some(unsafe { &mut *self.base.offset(ofs as isize) })
        } else {
            None
        }
    }

    /// Unwrap the pointer without running the destructor
    ///
    /// This method retrieves the underlying pointer, and in the process
    /// destroys the CVec but without running the destructor. A use case
    /// would be transferring ownership of the buffer to a C function, as
    /// in this case you would not want to run the destructor.
    ///
    /// Note that if you want to access the underlying pointer without
    /// cancelling the destructor, you can simply call `transmute` on the return
    /// value of `get(0)`.
    pub unsafe fn into_inner(mut self) -> *mut T {
        self.dtor = None;
        self.base
    }

    /// Deprecated, use into_inner() instead
    #[deprecated = "renamed to into_inner()"]
    pub unsafe fn unwrap(self) -> *mut T { self.into_inner() }

    /// Returns the number of items in this vector.
    pub fn len(&self) -> usize { self.len }

    /// Returns whether this vector is empty.
    pub fn is_empty(&self) -> bool { self.len() == 0 }
}

impl<'b, T> AsSlice<T> for CVec<'b, T> {
    /// View the stored data as a slice.
    fn as_slice<'a>(&'a self) -> &'a [T] {
        unsafe {
            mem::transmute(raw::Slice { data: self.base as *const T, len: self.len })
        }
    }
}

#[cfg(test)]
mod tests {
    use prelude::v1::*;

    use super::CVec;
    use libc;
    use ptr;

    fn malloc(n: uint) -> CVec<u8> {
        unsafe {
            let mem = ptr::Unique(libc::malloc(n as libc::size_t));
            if mem.0.is_null() { ::alloc::oom() }

            CVec::new_with_dtor(mem.0 as *mut u8,
                                n,
                                move|| { libc::free(mem.0 as *mut libc::c_void); })
        }
    }

    #[test]
    fn test_basic() {
        let mut cv = malloc(16);

        *cv.get_mut(3).unwrap() = 8;
        *cv.get_mut(4).unwrap() = 9;
        assert_eq!(*cv.get(3).unwrap(), 8);
        assert_eq!(*cv.get(4).unwrap(), 9);
        assert_eq!(cv.len(), 16);
    }

    #[test]
    #[should_fail]
    fn test_panic_at_null() {
        unsafe {
            CVec::new(ptr::null_mut::<u8>(), 9);
        }
    }

    #[test]
    fn test_overrun_get() {
        let cv = malloc(16);

        assert!(cv.get(17).is_none());
    }

    #[test]
    fn test_overrun_set() {
        let mut cv = malloc(16);

        assert!(cv.get_mut(17).is_none());
    }

    #[test]
    fn test_unwrap() {
        unsafe {
            let cv = CVec::new_with_dtor(1 as *mut int,
                                         0,
                                         move|&:| panic!("Don't run this destructor!"));
            let p = cv.into_inner();
            assert_eq!(p, 1 as *mut int);
        }
    }

}
<|endoftext|>


<commit_before>#![feature(inner_deref)]

extern crate cargo_metadata;

use std::path::{PathBuf, Path};
use std::io::{self, Write};
use std::process::Command;
use std::fs::{self, File};

const CARGO_MIRI_HELP: &str = r#"Interprets bin crates

Usage:
    cargo miri [subcommand] [options] [--] [<opts>...]

Subcommands:
    run                      Run binaries (default)
    test                     Run tests
    setup                    Only perform automatic setup, but without asking questions (for getting a proper libstd)

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit

Other options are the same as `cargo rustc`.

The feature `cargo-miri` is automatically defined for convenience. You can use
it to configure the resource limits

    #![cfg_attr(feature = "cargo-miri", memory_size = 42)]

available resource limits are `memory_size`, `step_limit`, `stack_limit`
"#;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum MiriCommand {
    Run,
    Test,
    Setup,
}

fn show_help() {
    println!("{}", CARGO_MIRI_HELP);
}

fn show_version() {
    println!("miri {} ({} {})",
        env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE"));
}

fn show_error(msg: String) -> ! {
    eprintln!("fatal error: {}", msg);
    std::process::exit(1)
}

fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=cargo_metadata::Target> {
    // We need to get the manifest, and then the metadata, to enumerate targets.
    let manifest_path_arg = args.find(|val| {
        val.starts_with("--manifest-path=")
    });

    let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
        manifest_path_arg.as_ref().map(AsRef::as_ref),
    )
    {
        metadata
    } else {
        show_error(format!("error: Could not obtain cargo metadata."));
    };

    let manifest_path = manifest_path_arg.map(|arg| {
        PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))
    });

    let current_dir = std::env::current_dir();

    let package_index = metadata
        .packages
        .iter()
        .position(|package| {
            let package_manifest_path = Path::new(&package.manifest_path);
            if let Some(ref manifest_path) = manifest_path {
                package_manifest_path == manifest_path
            } else {
                let current_dir = current_dir.as_ref().expect(
                    "could not read current directory",
                );
                let package_manifest_directory = package_manifest_path.parent().expect(
                    "could not find parent directory of package manifest",
                );
                package_manifest_directory == current_dir
            }
        })
        .expect("could not find matching package");
    let package = metadata.packages.remove(package_index);

    // Finally we got the list of targets to build
    package.targets.into_iter()
}

fn ask(question: &str) {
    let mut buf = String::new();
    print!("{} [Y/n] ", question);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut buf).unwrap();
    match buf.trim().to_lowercase().as_ref() {
        "" | "y" | "yes" => {}, // proceed
        "n" | "no" => show_error(format!("Aborting as per your request")),
        a => show_error(format!("I do not understand `{}`", a))
    };
}

/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT.
/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already.
fn setup(ask_user: bool) {
    if std::env::var("MIRI_SYSROOT").is_ok() {
        return;
    }

    // First, we need xargo
    if Command::new("xargo").arg("--version").output().is_err()
    {
        if ask_user {
            ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?");
        } else {
            println!("Installing xargo: `cargo install xargo`");
        }
        if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() {
            show_error(format!("Failed to install xargo"));
        }
    }

    // Then, we also need rust-src.  Let's see if it is already installed.
    let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout;
    let sysroot = std::str::from_utf8(&sysroot[..]).unwrap();
    let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src");
    if !src.exists() {
        if ask_user {
            ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?");
        } else {
            println!("Installing rust-src component: `rustup component add rust-src`");
        }
        if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() {
            show_error(format!("Failed to install rust-src component"));
        }
    }

    // Next, we need our own libstd. We will do this work in ~/.miri.
    let dir = directories::UserDirs::new().unwrap().home_dir().join(".miri");
    if !dir.exists() {
        fs::create_dir(&dir).unwrap();
    }
    // The interesting bit: Xargo.toml
    File::create(dir.join("Xargo.toml")).unwrap()
        .write_all(br#"
[dependencies.std]
features = ["panic_unwind"]

[dependencies.test]
stage = 1
        "#).unwrap();
    // The boring bits: A dummy project for xargo
    File::create(dir.join("Cargo.toml")).unwrap()
        .write_all(br#"
[package]
name = "miri-xargo"
description = "A dummy project for building libstd with xargo."
version = "0.0.0"

[lib]
path = "lib.rs"
        "#).unwrap();
    File::create(dir.join("lib.rs")).unwrap();
    // Run xargo
    if !Command::new("xargo").arg("build").arg("-q")
        .current_dir(&dir)
        .env("RUSTFLAGS", miri::miri_default_args().join(" "))
        .env("XARGO_HOME", dir.to_str().unwrap())
        .status().unwrap().success()
    {
        show_error(format!("Failed to run xargo"));
    }

    // That should be it!
    std::env::set_var("MIRI_SYSROOT", dir.join("HOST"));
}

fn main() {
    // Check for version and help flags even when invoked as 'cargo-miri'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is when `cargo miri` is called.  We call `cargo rustc` for
        // each applicable target, but with the RUSTC env var set to the `cargo-miri`
        // binary so that we come back in the other branch, and dispatch
        // the invocations to rustc and miri, respectively.

        let (subcommand, skip) = match std::env::args().nth(2).deref() {
            Some("test") => (MiriCommand::Test, 3),
            Some("run") => (MiriCommand::Run, 3),
            Some("setup") => (MiriCommand::Setup, 3),
            // Default command, if there is an option or nothing
            Some(s) if s.starts_with("-") => (MiriCommand::Run, 2),
            None => (MiriCommand::Run, 2),
            // Unvalid command
            Some(s) => {
                show_error(format!("Unknown command `{}`", s))
            }
        };

        // We always setup
        let ask = subcommand != MiriCommand::Setup;
        setup(ask);

        // Now run the command.
        for target in list_targets(std::env::args().skip(skip)) {
            let args = std::env::args().skip(skip);
            let kind = target.kind.get(0).expect(
                "badly formatted cargo metadata: target::kind is an empty array",
            );
            match (subcommand, &kind[..]) {
                (MiriCommand::Test, "test") => {
                    // For test binaries we call `cargo rustc --test target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--test".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Test, "lib") => {
                    // For libraries we call `cargo rustc -- --test <rustc args>`
                    // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells
                    // rustc to build a test harness which calls all #[test] functions. We don't
                    // use the harness since we execute each #[test] function's MIR ourselves before
                    // compilation even completes, but this option is necessary to build the library.
                    if let Err(code) = process(
                        vec!["--".to_string(), "--test".to_string()].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Run, "bin") => {
                    // For ordinary binaries we call `cargo rustc --bin target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--bin".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                _ => {}
            }
        }
    } else {
        // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself:
        // Dependencies get dispatched to rustc, the final test/binary to miri.

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") {
            sysroot
        } else if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("RUST_SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust")
        };

        // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
        // without having to pass --sysroot or anything
        let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
            std::env::args().skip(1).collect()
        } else {
            std::env::args()
                .skip(1)
                .chain(Some("--sysroot".to_owned()))
                .chain(Some(sys_root))
                .collect()
        };
        args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));

        // this check ensures that dependencies are built but not interpreted and the final crate is
        // interpreted but not built
        let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata");

        let mut command = if miri_enabled {
            let mut path = std::env::current_exe().expect("current executable path invalid");
            path.set_file_name("miri");
            Command::new(path)
        } else {
            Command::new("rustc")
        };

        args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);

        match command.args(&args).status() {
            Ok(exit) => {
                if !exit.success() {
                    std::process::exit(exit.code().unwrap_or(42));
                }
            }
            Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
            Err(ref e) => panic!("error during rustc call: {:?}", e),
        }
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=dep-info,metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-miri""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<commit_msg>use proper platform cache dir<commit_after>#![feature(inner_deref)]

extern crate cargo_metadata;

use std::path::{PathBuf, Path};
use std::io::{self, Write};
use std::process::Command;
use std::fs::{self, File};

const CARGO_MIRI_HELP: &str = r#"Interprets bin crates

Usage:
    cargo miri [subcommand] [options] [--] [<opts>...]

Subcommands:
    run                      Run binaries (default)
    test                     Run tests
    setup                    Only perform automatic setup, but without asking questions (for getting a proper libstd)

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit

Other options are the same as `cargo rustc`.

The feature `cargo-miri` is automatically defined for convenience. You can use
it to configure the resource limits

    #![cfg_attr(feature = "cargo-miri", memory_size = 42)]

available resource limits are `memory_size`, `step_limit`, `stack_limit`
"#;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum MiriCommand {
    Run,
    Test,
    Setup,
}

fn show_help() {
    println!("{}", CARGO_MIRI_HELP);
}

fn show_version() {
    println!("miri {} ({} {})",
        env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE"));
}

fn show_error(msg: String) -> ! {
    eprintln!("fatal error: {}", msg);
    std::process::exit(1)
}

fn list_targets(mut args: impl Iterator<Item=String>) -> impl Iterator<Item=cargo_metadata::Target> {
    // We need to get the manifest, and then the metadata, to enumerate targets.
    let manifest_path_arg = args.find(|val| {
        val.starts_with("--manifest-path=")
    });

    let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(
        manifest_path_arg.as_ref().map(AsRef::as_ref),
    )
    {
        metadata
    } else {
        show_error(format!("error: Could not obtain cargo metadata."));
    };

    let manifest_path = manifest_path_arg.map(|arg| {
        PathBuf::from(Path::new(&arg["--manifest-path=".len()..]))
    });

    let current_dir = std::env::current_dir();

    let package_index = metadata
        .packages
        .iter()
        .position(|package| {
            let package_manifest_path = Path::new(&package.manifest_path);
            if let Some(ref manifest_path) = manifest_path {
                package_manifest_path == manifest_path
            } else {
                let current_dir = current_dir.as_ref().expect(
                    "could not read current directory",
                );
                let package_manifest_directory = package_manifest_path.parent().expect(
                    "could not find parent directory of package manifest",
                );
                package_manifest_directory == current_dir
            }
        })
        .expect("could not find matching package");
    let package = metadata.packages.remove(package_index);

    // Finally we got the list of targets to build
    package.targets.into_iter()
}

fn ask(question: &str) {
    let mut buf = String::new();
    print!("{} [Y/n] ", question);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut buf).unwrap();
    match buf.trim().to_lowercase().as_ref() {
        "" | "y" | "yes" => {}, // proceed
        "n" | "no" => show_error(format!("Aborting as per your request")),
        a => show_error(format!("I do not understand `{}`", a))
    };
}

/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT.
/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already.
fn setup(ask_user: bool) {
    if std::env::var("MIRI_SYSROOT").is_ok() {
        return;
    }

    // First, we need xargo
    if Command::new("xargo").arg("--version").output().is_err()
    {
        if ask_user {
            ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?");
        } else {
            println!("Installing xargo: `cargo install xargo`");
        }
        if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() {
            show_error(format!("Failed to install xargo"));
        }
    }

    // Then, we also need rust-src.  Let's see if it is already installed.
    let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout;
    let sysroot = std::str::from_utf8(&sysroot[..]).unwrap();
    let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src");
    if !src.exists() {
        if ask_user {
            ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?");
        } else {
            println!("Installing rust-src component: `rustup component add rust-src`");
        }
        if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() {
            show_error(format!("Failed to install rust-src component"));
        }
    }

    // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform.
    let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap();
    let dir = dirs.cache_dir();
    if !dir.exists() {
        fs::create_dir(&dir).unwrap();
    }
    // The interesting bit: Xargo.toml
    File::create(dir.join("Xargo.toml")).unwrap()
        .write_all(br#"
[dependencies.std]
features = ["panic_unwind"]

[dependencies.test]
stage = 1
        "#).unwrap();
    // The boring bits: A dummy project for xargo
    File::create(dir.join("Cargo.toml")).unwrap()
        .write_all(br#"
[package]
name = "miri-xargo"
description = "A dummy project for building libstd with xargo."
version = "0.0.0"

[lib]
path = "lib.rs"
        "#).unwrap();
    File::create(dir.join("lib.rs")).unwrap();
    // Run xargo
    if !Command::new("xargo").arg("build").arg("-q")
        .current_dir(&dir)
        .env("RUSTFLAGS", miri::miri_default_args().join(" "))
        .env("XARGO_HOME", dir.to_str().unwrap())
        .status().unwrap().success()
    {
        show_error(format!("Failed to run xargo"));
    }

    // That should be it!
    std::env::set_var("MIRI_SYSROOT", dir.join("HOST"));
}

fn main() {
    // Check for version and help flags even when invoked as 'cargo-miri'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is when `cargo miri` is called.  We call `cargo rustc` for
        // each applicable target, but with the RUSTC env var set to the `cargo-miri`
        // binary so that we come back in the other branch, and dispatch
        // the invocations to rustc and miri, respectively.

        let (subcommand, skip) = match std::env::args().nth(2).deref() {
            Some("test") => (MiriCommand::Test, 3),
            Some("run") => (MiriCommand::Run, 3),
            Some("setup") => (MiriCommand::Setup, 3),
            // Default command, if there is an option or nothing
            Some(s) if s.starts_with("-") => (MiriCommand::Run, 2),
            None => (MiriCommand::Run, 2),
            // Unvalid command
            Some(s) => {
                show_error(format!("Unknown command `{}`", s))
            }
        };

        // We always setup
        let ask = subcommand != MiriCommand::Setup;
        setup(ask);

        // Now run the command.
        for target in list_targets(std::env::args().skip(skip)) {
            let args = std::env::args().skip(skip);
            let kind = target.kind.get(0).expect(
                "badly formatted cargo metadata: target::kind is an empty array",
            );
            match (subcommand, &kind[..]) {
                (MiriCommand::Test, "test") => {
                    // For test binaries we call `cargo rustc --test target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--test".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Test, "lib") => {
                    // For libraries we call `cargo rustc -- --test <rustc args>`
                    // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells
                    // rustc to build a test harness which calls all #[test] functions. We don't
                    // use the harness since we execute each #[test] function's MIR ourselves before
                    // compilation even completes, but this option is necessary to build the library.
                    if let Err(code) = process(
                        vec!["--".to_string(), "--test".to_string()].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                (MiriCommand::Run, "bin") => {
                    // For ordinary binaries we call `cargo rustc --bin target -- <rustc args>`
                    if let Err(code) = process(
                        vec!["--bin".to_string(), target.name].into_iter().chain(
                            args,
                        ),
                    )
                    {
                        std::process::exit(code);
                    }
                }
                _ => {}
            }
        }
    } else {
        // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself:
        // Dependencies get dispatched to rustc, the final test/binary to miri.

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") {
            sysroot
        } else if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("RUST_SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust")
        };

        // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly
        // without having to pass --sysroot or anything
        let mut args: Vec<String> = if std::env::args().any(|s| s == "--sysroot") {
            std::env::args().skip(1).collect()
        } else {
            std::env::args()
                .skip(1)
                .chain(Some("--sysroot".to_owned()))
                .chain(Some(sys_root))
                .collect()
        };
        args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string));

        // this check ensures that dependencies are built but not interpreted and the final crate is
        // interpreted but not built
        let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata");

        let mut command = if miri_enabled {
            let mut path = std::env::current_exe().expect("current executable path invalid");
            path.set_file_name("miri");
            Command::new(path)
        } else {
            Command::new("rustc")
        };

        args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]);

        match command.args(&args).status() {
            Ok(exit) => {
                if !exit.success() {
                    std::process::exit(exit.code().unwrap_or(42));
                }
            }
            Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e),
            Err(ref e) => panic!("error during rustc call: {:?}", e),
        }
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=dep-info,metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-miri""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Dmitry Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Cloud API.

#[allow(unused_imports)]
use super::ApiResult;
use super::auth::AuthMethod;
#[cfg(feature = "compute")]
use super::compute::{Server, ServerQuery, ServerSummary};
use super::session::Session;

/// OpenStack cloud API.
#[derive(Debug, Clone)]
pub struct Cloud {
    session: Session
}

impl Cloud {
    /// Create a new cloud object with a given authentication plugin.
    pub fn new<Auth: AuthMethod + 'static>(auth_method: Auth) -> Cloud {
        Cloud {
            session: Session::new(auth_method)
        }
    }

    /// Convert this cloud into one using the given endpoint interface.
    pub fn with_endpoint_interface<S>(self, endpoint_interface: S)
            -> Cloud where S: Into<String> {
        Cloud {
            session: self.session.with_endpoint_interface(endpoint_interface)
        }
    }

    /// Session object.
    pub fn session(&self) -> &Session {
        &self.session
    }

    /// Extract the session object.
    pub fn into_session(self) -> Session {
        self.session
    }

    /// Find a server by its ID.
    #[cfg(feature = "compute")]
    pub fn get_server_by_id<Id: AsRef<str>>(&self, id: Id) -> ApiResult<Server> {
        Server::new(&self.session, id)
    }

    /// Build a query against server list.
    #[cfg(feature = "compute")]
    pub fn find_servers(&self) -> ServerQuery {
        ServerQuery::new(&self.session)
    }

    /// List all servers with an optional limit.
    #[cfg(feature = "compute")]
    pub fn list_servers(&self, limit: Option<usize>) -> ApiResult<Vec<ServerSummary>> {
        let mut query = self.find_servers();
        if let Some(l) = limit {
            query = query.with_limit(l);
        }
        query.fetch()
    }
}
<commit_msg>fear(cloud): add new_with_session and simplify list_servers<commit_after>// Copyright 2018 Dmitry Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Cloud API.

#[allow(unused_imports)]
use super::ApiResult;
use super::auth::AuthMethod;
#[cfg(feature = "compute")]
use super::compute::{Server, ServerQuery, ServerSummary};
use super::session::Session;

/// OpenStack cloud API.
#[derive(Debug, Clone)]
pub struct Cloud {
    session: Session
}

impl Cloud {
    /// Create a new cloud object with a given authentication plugin.
    pub fn new<Auth: AuthMethod + 'static>(auth_method: Auth) -> Cloud {
        Cloud::new_with_session(Session::new(auth_method))
    }

    /// Create a new cloud object with a given session.
    pub fn new_with_session(session: Session) -> Cloud {
        Cloud {
            session: session
        }
    }

    /// Convert this cloud into one using the given endpoint interface.
    pub fn with_endpoint_interface<S>(self, endpoint_interface: S)
            -> Cloud where S: Into<String> {
        Cloud {
            session: self.session.with_endpoint_interface(endpoint_interface)
        }
    }

    /// Session object.
    pub fn session(&self) -> &Session {
        &self.session
    }

    /// Extract the session object.
    pub fn into_session(self) -> Session {
        self.session
    }

    /// Find a server by its ID.
    #[cfg(feature = "compute")]
    pub fn get_server_by_id<Id: AsRef<str>>(&self, id: Id) -> ApiResult<Server> {
        Server::new(&self.session, id)
    }

    /// Build a query against server list.
    #[cfg(feature = "compute")]
    pub fn find_servers(&self) -> ServerQuery {
        ServerQuery::new(&self.session)
    }

    /// List all servers with an optional limit.
    #[cfg(feature = "compute")]
    pub fn list_servers(&self) -> ApiResult<Vec<ServerSummary>> {
        // TODO(dtantsur): pagination
        self.find_servers().fetch()
    }
}
<|endoftext|>