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

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11.0-pre"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/")]

#![feature(plugin_registrar, managed_boxes)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use rustc::plugin::Registry;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fourcc", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>rustc: Obsolete the `@` syntax entirely<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(plugin)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11.0-pre"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/")]

#![feature(plugin_registrar, managed_boxes)]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use rustc::plugin::Registry;

use std::gc::Gc;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fourcc", expand_syntax_ext);
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt,
             tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>


<commit_before>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num, hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost > other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            (a.r-b.r)*(a.r-b.r) + (a.g-b.g)*(a.g-b.g) + (a.b-b.b)*(a.b-b.b) ) as float)
}

fn findParent(map: &arc::RWArc<~[int]>, a: int) -> int {
    do map.read() |colors| {
        if colors[a] < 0 {
            a
        } else {
            findParent(map, colors[a])
        }
    }
}

fn setParent(map: &arc::RWArc<~[int]>, ind: int, val: int) {
    let mut tmp: int = -1;
    do map.write() |colors| {
        tmp = colors[ind];
        colors[ind] = val;
    }
    if tmp >= 0 {
        setParent(map, tmp, val);
    }
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    let mut retval: ~[~[Pixel]] = ~[];

    let file: &str = filename.to_owned();
//    let file2: ~str = file.to_owned();
    let split_filename: ~[&str] = file.split_iter('.').collect();
    let file_data: &str = split_filename[0] + ".txt";

    println(fmt!("The image name is [%?]", file));
    println(fmt!("The image data will be stored at [%?]", file_data));

    //read in the .txt associated with the file title
    let path = &PosixPath(file_data);

    match std::io::file_reader(path) {
	Ok(reader) => {
	    //run the java program to process the image
/*	    let program: &str = "java ImageReader";
	    let argv: ~[~str] = ~[file2];
	    let mut prog = std::run::Process::new(program, argv,
		std::run::ProcessOptions {
			env: None,
			dir: None,
			in_fd: None,
			out_fd: None,
			err_fd: None
		}
	    );
	    prog.finish();
*/
	    //parse out the array dimensions
    	    let dimensions_str: &str = reader.read_line();
    	    println(fmt!("dimensons: %s",dimensions_str));
	    let mut h: int = 0;
	    let mut w: int = 0;
	    match dimensions_str[0] as char {
		'H' => {
		    let split_dim: ~[&str] = dimensions_str.split_iter('W').collect();
		    h = from_str(split_dim[0].slice(1,split_dim[0].len())).unwrap();
		    w = from_str(split_dim[1]).unwrap();
		    println(fmt!("Dimensions passed: H %? W %?",h,w));
		    //let retval: ~[ ~[Pixel, ..w], ..h];
		}
		_ => {println("Dimensions corrupted! Abort");}
	    }

	    //fill in the retVal array with pixel data
            //let mut rowfirst = false;
	    for row in range(0,h){
//                if(!rowfirst) {
                retval.push(~[]);
                //rowfirst = true; }
		for col in range(0,w){
	    	    if !reader.eof() {
			let line: &str = reader.read_line();
			//println(line);
			let rpos:uint = match line.find('R') { Some(n)=>n,None=>line.len() };
			let gpos:uint = match line.find('G') { Some(n)=>n,None=>line.len() };
			let bpos:uint = match line.find('B') { Some(n)=>n,None=>line.len() };

			if rpos == line.len() || gpos == line.len() || bpos == line.len() {
			    println("Pixel data corrupted! Abort");
			}

			let R:int = from_str(line.slice(rpos+1,gpos)).unwrap();
			let G:int = from_str(line.slice(gpos+1,bpos)).unwrap();
			let B:int = from_str(line.slice(bpos+1,line.len())).unwrap();

			//println(fmt!("R %? G %? B %?",R,G,B));

			//fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
			retval[row].push(Pixel::new(R,G,B,col,row));

		    }
		    else {
			println("Data file corrupted! Abort");
		    }
		}
	    }
	},
	Err(err)   => { fail!(err) }
    }

    retval
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);
    let height = pixels.len() as int;
    let width = pixels[0].len() as int;

    println(fmt!("Dimensions received: H %? W %?",height,width));

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[];
    for h in range(0,height){
	find_arcs.push(~[]);
        for w in range(0,width){
 //           println(fmt!("pix %?",pixels[h][w]));
	    find_arcs[h].push(arc::RWArc::new(pixels[h][w]));
	}
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let mut colormap:  ~[int] = ~[];
    let corners = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];

    let mut color_index = 0;
    for &corner in corners.iter(){
        let (a,b) = corner;
        do arcs[b][a].write |pix| {
            pix.color = color_index;
        }
        color_index+=1;
        colormap.push(-1);
    }

    let colormap_arc: arc::RWArc<~[int]> =  arc::RWArc::new(colormap);

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        let shared_colormap = colormap_arc.clone();
        do spawn { // split into threads here
            let c = a;
            let d = b;
            let mut x=a;
            let mut y=b;

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();
            let mut newvisit: bool = true;
            let mut boundaries: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut color: int = -1;
            do shared_arcs[b][a].read |pix| {
                color = pix.color;
            }

            println(fmt!("start at (%i,%i): color = %i",c,d,color));

            loop {
                //  at most once each:
                //   visit the next vertex (determined by the last edge we chose or the starting vertex) to claim its neighbors and add its edges to our queue
                //   pop the next edge off the queue, which contains all of the edges between vertices claimed by the local thread

                if(newvisit){ // if the next vertex has not previously been visited to claim neighbors and add edges
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x-1,y)]; // potential neighbors
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking on neighbors to only select valid edges
                            let mut newvertex = false;
                            let mut colored = false;
                            do shared_arcs[z][w].read |dest| {
                                if dest.color >= 0 {
                                    colored = true; //vertex has been previously claimed
                                }
                            }
                            if !colored { // this thread will claim the unclaimed vertex
                                do shared_arcs[z][w].write |dest| {
                                    if dest.color < 0 {
                                        dest.color = color;
                                        newvertex = true;
                                    } else {
                                        // edge has been claimed during a race since we last checked. add to supervertex boundary
                                        colored = true;
                                    }
                                }
                            }
                            if colored {
                                // we have found an edge that crosses a cut!
                                // here, somehow collect these edges for contraction later
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        if dest.color != color {
                                            boundaries.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                            // println(fmt!("%?\n-->%?",src,dest));
                                        }
                                    }
                                }
                            }
                            if newvertex { // we have an unvisited but previously claimed vertex
                                // add the edge to our local edges queue
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop(); // should fail only when we've exhausted all the edges in our queue, i.e. this thread is done running Prim
                match edge {
                    Some(e) => {
                        //println(fmt!("(%i,%i) pop (%i,%i)-%f-(%i,%i)",c,d,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
                        let coord = (e.dest.x,e.dest.y);
                        if !visited.contains_key(&coord){
                            // use visited hashmap to figure out if we're at a new vertex or a previously seen one
                            visited.insert(coord,true); //add to growing spanning forest
                            x = e.dest.x; // update search coordinates for next iteration
                            y = e.dest.y;
                            newvisit = true; // update flag to claim new vertex's neighbors
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }

            loop {
                match boundaries.maybe_pop() {
                    Some(e) =>
                        {
                        do shared_arcs[e.dest.y][e.dest.x].read |dest| {
                            do shared_arcs[e.source.y][e.source.x].read |src| {
                                println(fmt!("boundary (%i,%i:%i)-%f-(%i,%i:%i)",src.x,src.y,src.color,e.cost,dest.x,dest.y,dest.color));
                            }
                        }
                    }
                    None => { break; }
                }
            }

        }
    }

    for h in range(0,height){
        for w in range(0,width){
            do arcs[h][w].read |pix| {
        //        println(fmt!("color(%i,%i) %i",w,h,pix.color));
	    }
        }
    }
}
<commit_msg>boruvka contractions appear to be working.<commit_after>/**
Katy Williamson kcw4sn
Ben Terner bt3ze
@virginia.edu

Final Project for CS4414 - Operating Systems
A parallel MST implementation on images in Rust

*/

/*
some documentation:
Pixel object is composed of r,g,b values, a color, and an x,y index that takes the place of its adjacency list
Point is just an (x,y) value to denote a pixel's location
Edge contains two points: source and dest, along with the edge cost between them

*/

extern mod extra;
use std::{os, num, hashmap} ;
use extra::{arc,priority_queue};

struct Pixel{
    r: int,
    b: int,
    g: int,
    color: int,
    x: int,
    y: int
}

impl Pixel {
    fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
        Pixel{
            r: red,
            b: blue,
            g: green,
            color: -1,
            x: x,
            y: y
        }
    }
}

impl Clone for Pixel{
    fn clone(&self) -> Pixel {
        Pixel{
            r: self.r,
            b: self.b,
            g: self.g,
            color: self.color,
            x: self.x,
            y: self.y
        }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point{
    fn new(x: int, y: int)-> Point {
        Point {
            x: x,
            y: y
        }
    }
}

struct Edge {
    source: Point,
    dest: Point,
    cost: float
}

impl Edge {
    fn new(s: Point, d: Point, cost: float) -> Edge {
        Edge {
            source: s,
            dest: d,
            cost: cost
        }
    }
}

impl Ord for Edge {
    fn lt(&self, other: &Edge) -> bool {
        self.cost > other.cost
    }
}

fn edgeCost(a: &Pixel, b: &Pixel) -> float {
    num::sqrt( (
            (a.r-b.r)*(a.r-b.r) + (a.g-b.g)*(a.g-b.g) + (a.b-b.b)*(a.b-b.b) ) as float)
}

fn findParent(map: &arc::RWArc<~[int]>, a: int) -> int {
    do map.read() |colors| {
        if colors[a] < 0 {
            a
        } else {
            findParent(map, colors[a])
        }
    }
}

fn setParent(map: &arc::RWArc<~[int]>, ind: int, val: int) {
    let mut tmp: int = -1;
    do map.write() |colors| {
        tmp = colors[ind];
        colors[ind] = val;
    }
    if tmp >= 0 {
        setParent(map, tmp, val);
    }
}

fn readImage( filename: &~str) -> ~ [ ~[Pixel]] {
    let mut retval: ~[~[Pixel]] = ~[];

    let file: &str = filename.to_owned();
//    let file2: ~str = file.to_owned();
    let split_filename: ~[&str] = file.split_iter('.').collect();
    let file_data: &str = split_filename[0] + ".txt";

    println(fmt!("The image name is [%?]", file));
    println(fmt!("The image data will be stored at [%?]", file_data));

    //read in the .txt associated with the file title
    let path = &PosixPath(file_data);

    match std::io::file_reader(path) {
	Ok(reader) => {
	    //run the java program to process the image
/*	    let program: &str = "java ImageReader";
	    let argv: ~[~str] = ~[file2];
	    let mut prog = std::run::Process::new(program, argv,
		std::run::ProcessOptions {
			env: None,
			dir: None,
			in_fd: None,
			out_fd: None,
			err_fd: None
		}
	    );
	    prog.finish();
*/
	    //parse out the array dimensions
    	    let dimensions_str: &str = reader.read_line();
    	    println(fmt!("dimensons: %s",dimensions_str));
	    let mut h: int = 0;
	    let mut w: int = 0;
	    match dimensions_str[0] as char {
		'H' => {
		    let split_dim: ~[&str] = dimensions_str.split_iter('W').collect();
		    h = from_str(split_dim[0].slice(1,split_dim[0].len())).unwrap();
		    w = from_str(split_dim[1]).unwrap();
		    println(fmt!("Dimensions passed: H %? W %?",h,w));
		    //let retval: ~[ ~[Pixel, ..w], ..h];
		}
		_ => {println("Dimensions corrupted! Abort");}
	    }

	    //fill in the retVal array with pixel data
            //let mut rowfirst = false;
	    for row in range(0,h){
//                if(!rowfirst) {
                retval.push(~[]);
                //rowfirst = true; }
		for col in range(0,w){
	    	    if !reader.eof() {
			let line: &str = reader.read_line();
			//println(line);
			let rpos:uint = match line.find('R') { Some(n)=>n,None=>line.len() };
			let gpos:uint = match line.find('G') { Some(n)=>n,None=>line.len() };
			let bpos:uint = match line.find('B') { Some(n)=>n,None=>line.len() };

			if rpos == line.len() || gpos == line.len() || bpos == line.len() {
			    println("Pixel data corrupted! Abort");
			}

			let R:int = from_str(line.slice(rpos+1,gpos)).unwrap();
			let G:int = from_str(line.slice(gpos+1,bpos)).unwrap();
			let B:int = from_str(line.slice(bpos+1,line.len())).unwrap();

			//println(fmt!("R %? G %? B %?",R,G,B));

			//fn new(red: int, blue: int, green: int, x: int, y: int) -> Pixel {
			retval[row].push(Pixel::new(R,G,B,col,row));

		    }
		    else {
			println("Data file corrupted! Abort");
		    }
		}
	    }
	},
	Err(err)   => { fail!(err) }
    }

    retval
}

fn main(){
    let argv =  os::args();
    println(argv.to_str());

    let pixels: ~[ ~[Pixel] ] = readImage(&argv[1]);
    let height = pixels.len() as int;
    let width = pixels[0].len() as int;

    println(fmt!("Dimensions received: H %? W %?",height,width));

    let mut find_arcs: ~[ ~[arc::RWArc<Pixel>] ] =  ~[];
    for h in range(0,height){
	find_arcs.push(~[]);
        for w in range(0,width){
 //           println(fmt!("pix %?",pixels[h][w]));
	    find_arcs[h].push(arc::RWArc::new(pixels[h][w]));
	}
    }

    let arcs = find_arcs; // now we have an immutable array that can be shared

    let mut colormap:  ~[int] = ~[];
    let corners = [ (0,0),(width-1,0),(0,height-1),(width-1,height-1) ];

    let mut color_index = 0;
    for &corner in corners.iter(){
        let (a,b) = corner;
        do arcs[b][a].write |pix| {
            pix.color = color_index;
        }
        color_index+=1;
        colormap.push(-1);
    }

    let colormap_arc: arc::RWArc<~[int]> =  arc::RWArc::new(colormap);

    for &corner in corners.iter() {
        let (a,b) = corner;
        let shared_arcs = arcs.clone();
        let shared_colormap = colormap_arc.clone();
        do spawn { // split into threads here
            let c = a;
            let d = b;
            let mut x=a;
            let mut y=b;

            let mut queue: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut visited: hashmap::HashMap<(int,int),bool> = hashmap::HashMap::new();
            let mut newvisit: bool = true;
            let mut boundaries: priority_queue::PriorityQueue<Edge> =  priority_queue::PriorityQueue::new();
            let mut color: int = -1;
            do shared_arcs[b][a].read |pix| {
                color = pix.color;
            }

            println(fmt!("start at (%i,%i): color = %i",c,d,color));

            loop {
                //  at most once each:
                //   visit the next vertex (determined by the last edge we chose or the starting vertex) to claim its neighbors and add its edges to our queue
                //   pop the next edge off the queue, which contains all of the edges between vertices claimed by the local thread

                if(newvisit){ // if the next vertex has not previously been visited to claim neighbors and add edges
                    let neighbors = [ (x,y-1),(x+1,y), (x,y+1), (x-1,y)]; // potential neighbors
                    for &coord in neighbors.iter() {
                        let (w,z) = coord;
                        if w >=0 && w < width && z >=0 && z < height { // bounds checking on neighbors to only select valid edges
                            let mut newvertex = false;
                            let mut colored = false;
                            do shared_arcs[z][w].read |dest| {
                                if dest.color >= 0 {
                                    colored = true; //vertex has been previously claimed
                                }
                            }
                            if !colored { // this thread will claim the unclaimed vertex
                                do shared_arcs[z][w].write |dest| {
                                    if dest.color < 0 {
                                        dest.color = color;
                                        newvertex = true;
                                    } else {
                                        // edge has been claimed during a race since we last checked. add to supervertex boundary
                                        colored = true;
                                    }
                                }
                            }
                            if colored {
                                // we have found an edge that crosses a cut!
                                // here, somehow collect these edges for contraction later
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        if dest.color != color {
                                            boundaries.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                            // println(fmt!("%?\n-->%?",src,dest));
                                        }
                                    }
                                }
                            }
                            if newvertex { // we have an unvisited but previously claimed vertex
                                // add the edge to our local edges queue
                                do shared_arcs[y][x].read |src| {
                                    do shared_arcs[z][w].read |dest| {
                                        queue.push( Edge::new(Point::new(x,y),Point::new(w,z),edgeCost(src,dest)));
                                    }
                                }
                            }
                        }
                    }
                }

                let edge = queue.maybe_pop(); // should fail only when we've exhausted all the edges in our queue, i.e. this thread is done running Prim
                match edge {
                    Some(e) => {
                        //println(fmt!("(%i,%i) pop (%i,%i)-%f-(%i,%i)",c,d,e.source.x,e.source.y,e.cost,e.dest.x,e.dest.y));
                        let coord = (e.dest.x,e.dest.y);
                        if !visited.contains_key(&coord){
                            // use visited hashmap to figure out if we're at a new vertex or a previously seen one
                            visited.insert(coord,true); //add to growing spanning forest
                            x = e.dest.x; // update search coordinates for next iteration
                            y = e.dest.y;
                            newvisit = true; // update flag to claim new vertex's neighbors
                        } else {
                            newvisit = false;
                        }
                    },
                    None => { break; } // this should execute at the end when there are no more unvisited or uncolored nodes for a thread
                }
            }

            loop {
                match boundaries.maybe_pop() {
                    Some(e) =>
                        {
                        do shared_arcs[e.dest.y][e.dest.x].read |dest| {
                            do shared_arcs[e.source.y][e.source.x].read |src| {
                                println(fmt!("boundary (%i,%i:%i)-%f-(%i,%i:%i)",src.x,src.y,src.color,e.cost,dest.x,dest.y,dest.color));
                                let dest_parent = findParent(&shared_colormap,dest.color);
                                let src_parent =  findParent(&shared_colormap,src.color);
                                if src_parent != dest_parent {
                                    setParent(&shared_colormap,src.color,dest_parent);
                                    println(fmt!("bridge: (%i,%i:%i->%i)-(%i,%i:%i->%i) : %f",src.x,src.y,src.color,src_parent,dest.x,dest.y,dest.color,dest_parent, e.cost));
                                }
                            }
                        }
                    }
                    None => { break; }
                }
            }

        }
    }

    for h in range(0,height){
        for w in range(0,width){
            do arcs[h][w].read |pix| {
        //        println(fmt!("color(%i,%i) %i",w,h,pix.color));
	    }
        }
    }
}
<|endoftext|>


<commit_before>//! Macros to define CSS properties.

pub trait Property<T> {
    fn inherits_automatically() -> bool;
    fn compute(&self, _: &T) -> Self;
}

/// Generates a property definition that simply parses strings to enum variants
/// or to a tuple struct of the given type.
///
/// For example, the SVG spec defines the `stroke-linejoin` property
/// to have possible values `miter | round | bevel | inherit`, with a default
/// of `miter`.  We can define the property like this:
///
/// ```ignore
/// make_property!(
/// StrokeLinejoin,
/// default: Miter,
///
/// "miter" => Miter,
/// "round" => Round,
/// "bevel" => Bevel,
/// );
/// ```
///
/// The macro will generate a `StrokeLinejoin` enum with the provided
/// variants.  It will generate an `impl Default for StrokeLinejoin`
/// with the provided `default:` value.  Finally, it will generate an
/// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, with
/// `type Err = ValueErrorKind`.
#[macro_export]
macro_rules! make_property {
    ($computed_values_type: ty,
     $name: ident,
     default: $default: ident,
     inherits_automatically: $inherits_automatically: expr,
     identifiers:
     $($str_prop: expr => $variant: ident,)+
    ) => {
        #[derive(Debug, Copy, Clone, PartialEq)]
        pub enum $name {
            $($variant),+
        }

        impl_default!($name, $name::$default);
        impl_property!($computed_values_type, $name, $inherits_automatically);

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok(parse_identifiers!(
                    parser,
                    $($str_prop => $name::$variant,)+
                )?)
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype_parse: $type: ty,
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($computed_values_type, $name, $inherits_automatically);

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok($name(<$type as crate::parsers::Parse>::parse(parser)?))
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     newtype_parse: $type: ty,
     property_impl: { $prop: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));

        $prop

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok($name(<$type as crate::parsers::Parse>::parse(parser)?))
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     newtype: $type: ty,
     property_impl: { $prop: item },
     parse_impl: { $parse: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));

        $prop

        $parse
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype: $type: ty,
     parse_impl: { $parse: item },
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($computed_values_type, $name, $inherits_automatically);

        $parse
    };

    ($computed_values_type: ty,
     $name: ident,
     inherits_automatically: $inherits_automatically: expr,
     fields: {
       $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
     }
     parse_impl: { $parse: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name {
            $(pub $field_name: $field_type),+
        }

        impl_default!($name, $name { $($field_name: $field_default),+ });
        impl_property!($computed_values_type, $name, $inherits_automatically);

        $parse
    };
}

macro_rules! impl_default {
    ($name:ident, $default:expr) => {
        impl Default for $name {
            fn default() -> $name {
                $default
            }
        }
    };
}

macro_rules! impl_property {
    ($computed_values_type:ty, $name:ident, $inherits_automatically:expr) => {
        impl crate::property_macros::Property<$computed_values_type> for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }

            fn compute(&self, _v: &$computed_values_type) -> Self {
                self.clone()
            }
        }
    };
}

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

    use crate::parsers::Parse;
    use cssparser::RGBA;

    #[test]
    fn check_identifiers_property() {
        make_property! {
            (),
            Foo,
            default: Def,
            inherits_automatically: true,

            identifiers:
            "def" => Def,
            "bar" => Bar,
            "baz" => Baz,
        }

        assert_eq!(<Foo as Default>::default(), Foo::Def);
        assert_eq!(<Foo as Property<()>>::inherits_automatically(), true);
        assert!(<Foo as Parse>::parse_str("blargh").is_err());
        assert_eq!(<Foo as Parse>::parse_str("bar"), Ok(Foo::Bar));
    }

    #[test]
    fn check_compute() {
        make_property! {
            RGBA,
            AddColor,
            default: RGBA::new(1, 1, 1, 1),
            newtype_parse: RGBA,
            property_impl: {
                impl Property<RGBA> for AddColor {
                    fn inherits_automatically() -> bool {
                        true
                    }

                    fn compute(&self, v: &RGBA) -> Self {
                        AddColor(RGBA::new(
                            self.0.red + v.red,
                            self.0.green + v.green,
                            self.0.blue + v.blue,
                            self.0.alpha + v.alpha
                        ))
                    }
                }
            }
        }

        let color = RGBA::new(1, 1, 1, 1);
        let a = <AddColor as Parse>::parse_str("#02030405").unwrap();
        let b = a.compute(&color);

        assert_eq!(b, AddColor(RGBA::new(3, 4, 5, 6)));
    }
}
<commit_msg>repr(C) the enums created by the make_property macro<commit_after>//! Macros to define CSS properties.

pub trait Property<T> {
    fn inherits_automatically() -> bool;
    fn compute(&self, _: &T) -> Self;
}

/// Generates a property definition that simply parses strings to enum variants
/// or to a tuple struct of the given type.
///
/// For example, the SVG spec defines the `stroke-linejoin` property
/// to have possible values `miter | round | bevel | inherit`, with a default
/// of `miter`.  We can define the property like this:
///
/// ```ignore
/// make_property!(
/// StrokeLinejoin,
/// default: Miter,
///
/// "miter" => Miter,
/// "round" => Round,
/// "bevel" => Bevel,
/// );
/// ```
///
/// The macro will generate a `StrokeLinejoin` enum with the provided
/// variants.  It will generate an `impl Default for StrokeLinejoin`
/// with the provided `default:` value.  Finally, it will generate an
/// `impl Parse for StrokeLinejoin`, from `parsers::Parse`, with
/// `type Err = ValueErrorKind`.
#[macro_export]
macro_rules! make_property {
    ($computed_values_type: ty,
     $name: ident,
     default: $default: ident,
     inherits_automatically: $inherits_automatically: expr,
     identifiers:
     $($str_prop: expr => $variant: ident,)+
    ) => {
        #[derive(Debug, Copy, Clone, PartialEq)]
        #[repr(C)]
        pub enum $name {
            $($variant),+
        }

        impl_default!($name, $name::$default);
        impl_property!($computed_values_type, $name, $inherits_automatically);

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok(parse_identifiers!(
                    parser,
                    $($str_prop => $name::$variant,)+
                )?)
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype_parse: $type: ty,
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($computed_values_type, $name, $inherits_automatically);

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok($name(<$type as crate::parsers::Parse>::parse(parser)?))
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     newtype_parse: $type: ty,
     property_impl: { $prop: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));

        $prop

        impl crate::parsers::Parse for $name {
            fn parse<'i>(parser: &mut ::cssparser::Parser<'i, '_>) -> Result<$name, crate::error::ParseError<'i>> {
                Ok($name(<$type as crate::parsers::Parse>::parse(parser)?))
            }
        }
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     newtype: $type: ty,
     property_impl: { $prop: item },
     parse_impl: { $parse: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));

        $prop

        $parse
    };

    ($computed_values_type: ty,
     $name: ident,
     default: $default: expr,
     inherits_automatically: $inherits_automatically: expr,
     newtype: $type: ty,
     parse_impl: { $parse: item },
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name(pub $type);

        impl_default!($name, $name($default));
        impl_property!($computed_values_type, $name, $inherits_automatically);

        $parse
    };

    ($computed_values_type: ty,
     $name: ident,
     inherits_automatically: $inherits_automatically: expr,
     fields: {
       $($field_name: ident : $field_type: ty, default: $field_default : expr,)+
     }
     parse_impl: { $parse: item }
    ) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $name {
            $(pub $field_name: $field_type),+
        }

        impl_default!($name, $name { $($field_name: $field_default),+ });
        impl_property!($computed_values_type, $name, $inherits_automatically);

        $parse
    };
}

macro_rules! impl_default {
    ($name:ident, $default:expr) => {
        impl Default for $name {
            fn default() -> $name {
                $default
            }
        }
    };
}

macro_rules! impl_property {
    ($computed_values_type:ty, $name:ident, $inherits_automatically:expr) => {
        impl crate::property_macros::Property<$computed_values_type> for $name {
            fn inherits_automatically() -> bool {
                $inherits_automatically
            }

            fn compute(&self, _v: &$computed_values_type) -> Self {
                self.clone()
            }
        }
    };
}

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

    use crate::parsers::Parse;
    use cssparser::RGBA;

    #[test]
    fn check_identifiers_property() {
        make_property! {
            (),
            Foo,
            default: Def,
            inherits_automatically: true,

            identifiers:
            "def" => Def,
            "bar" => Bar,
            "baz" => Baz,
        }

        assert_eq!(<Foo as Default>::default(), Foo::Def);
        assert_eq!(<Foo as Property<()>>::inherits_automatically(), true);
        assert!(<Foo as Parse>::parse_str("blargh").is_err());
        assert_eq!(<Foo as Parse>::parse_str("bar"), Ok(Foo::Bar));
    }

    #[test]
    fn check_compute() {
        make_property! {
            RGBA,
            AddColor,
            default: RGBA::new(1, 1, 1, 1),
            newtype_parse: RGBA,
            property_impl: {
                impl Property<RGBA> for AddColor {
                    fn inherits_automatically() -> bool {
                        true
                    }

                    fn compute(&self, v: &RGBA) -> Self {
                        AddColor(RGBA::new(
                            self.0.red + v.red,
                            self.0.green + v.green,
                            self.0.blue + v.blue,
                            self.0.alpha + v.alpha
                        ))
                    }
                }
            }
        }

        let color = RGBA::new(1, 1, 1, 1);
        let a = <AddColor as Parse>::parse_str("#02030405").unwrap();
        let b = a.compute(&color);

        assert_eq!(b, AddColor(RGBA::new(3, 4, 5, 6)));
    }
}
<|endoftext|>


<commit_before>//! To run a LOGO program, run:
//!     cargo run --example logo_interpreter -- my_logo_program.txt

extern crate turtle;

use turtle::Turtle;
use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

fn main() {
    let mut turtle = Turtle::new();

    let args: Vec<String> = env::args().collect();

    if args.len() != 2 {
        println!("Interactive LOGO Mode.\nType the commands in stdin.\nPress '^C' (cmd/ctrl+C) to exit");
        let stdin = io::stdin();
        let mut reader = BufReader::new(stdin);
        loop {
            let mut buffer = String::new();
            let _ = reader
                .read_line(&mut buffer)
                .expect("Unable read input from stdin");
                let cmd_args = buffer.split_whitespace();
                handle_command(&mut turtle, cmd_args);
        }
    }

    let path = &args[1];
    let file = File::open(path).expect("Could not open provided program");
    let mut reader = BufReader::new(file);
    loop {
        let mut buffer = String::new();
        let read_bytes = reader
            .read_line(&mut buffer)
            .expect("Unable read input file");
        if read_bytes == 0 {
            // Reached EOF, stop interpreter
            break;
        }

        let cmd_args = buffer.split_whitespace();
        handle_command(&mut turtle, cmd_args);
    }
}

fn handle_command<'a, A: Iterator<Item = &'a str>>(turtle: &mut Turtle, mut args: A) {
    while let Some(command) = args.next() {
        match command {
            "fd" | "forward" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expected a distance value after fd/forward command"),
                );
                turtle.forward(distance);
            },
            "bk" | "back" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after bk/back command"),
                );
                turtle.backward(distance);
            },
            "lt" | "left" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after lt/left command"),
                );
                turtle.left(distance);
            },
            "rt" | "right" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after rt/right command"),
                );
                turtle.right(distance);
            },
            _ => unimplemented!("Use of invalid or unsupported LOGO command"),
        }
    }
}

fn parse_distance(s: &str) -> f64 {
    let dist: f64 = s.parse().expect("Not a valide number");
    dist
}
<commit_msg>remove code duplication<commit_after>//! To run a LOGO program, run:
//!     cargo run --example logo_interpreter -- my_logo_program.txt

extern crate turtle;

use turtle::Turtle;
use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

fn main() {
    let mut turtle = Turtle::new();

    let args: Vec<String> = env::args().collect();

    if args.len() != 2 {
        println!(
            "Interactive LOGO Mode.\nType the commands in stdin.\nPress '^C' (cmd/ctrl+C) to exit"
        );
        let stdin = io::stdin();
        interpret(&mut turtle, stdin)
    }
    else {
        let path = &args[1];
        let file = File::open(path).expect("Could not open provided program");
        interpret(&mut turtle, file)
    }
}

fn interpret<R: io::Read>(turtle: &mut Turtle, input: R) {
    let mut reader = BufReader::new(input);
    loop {
        let mut buffer = String::new();
        let read_bytes = reader.read_line(&mut buffer)
            .expect("Unable read input");
        if read_bytes == 0 {
            // Reached EOF, break loop
            break;
        }
        let cmd_args = buffer.split_whitespace();
        handle_command(turtle, cmd_args);
    }
}

fn handle_command<'a, A: Iterator<Item = &'a str>>(turtle: &mut Turtle, mut args: A) {
    while let Some(command) = args.next() {
        match command
        {
            "fd" | "forward" => {
                let distance = parse_distance(args.next()
                    .expect("Expected a distance value after fd/forward command")
                );
                turtle.forward(distance);
            },
            "bk" | "back" => {
                let distance = parse_distance(args.next()
                    .expect("Expect a distance value after bk/back command")
                );
                turtle.backward(distance);
            },
            "lt" | "left" => {
                let distance = parse_distance(args.next()
                    .expect("Expect a distance value after lt/left command")
                );
                turtle.left(distance);
            },
            "rt" | "right" => {
                let distance = parse_distance(args.next()
                    .expect("Expect a distance value after rt/right command")
                );
                turtle.right(distance);
            },
            _ => unimplemented!("Use of invalid or unsupported LOGO command"),
        }
    }
}

fn parse_distance(s: &str) -> f64 {
    let dist: f64 = s.parse().expect("Not a valid number");
    dist
}
<|endoftext|>


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

use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::display_list::stacking_context::{
    ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode,
    StackingContextBuilder,
};
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2;
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Display, DisplayGeneratingBox};
use crate::DefiniteContainingBlock;
use app_units::Au;
use euclid::default::{Point2D, Rect, Size2D};
use gfx_traits::print_tree::PrintTree;
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style_traits::CSSPixel;

#[derive(Serialize)]
pub struct BoxTreeRoot(BlockFormattingContext);

#[derive(Serialize)]
pub struct FragmentTreeRoot {
    /// The children of the root of the fragment tree.
    children: Vec<ArcRefCell<Fragment>>,

    /// The scrollable overflow of the root of the fragment tree.
    scrollable_overflow: PhysicalRect<Length>,

    /// The containing block used in the layout of this fragment tree.
    initial_containing_block: PhysicalRect<Length>,
}

impl BoxTreeRoot {
    pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
    where
        Node: 'dom + Copy + LayoutNode<'dom> + Send + Sync,
    {
        let (contains_floats, boxes) = construct_for_root_element(&context, root_element);
        Self(BlockFormattingContext {
            contains_floats: contains_floats == ContainsFloats::Yes,
            contents: BlockContainer::BlockLevelBoxes(boxes),
        })
    }
}

fn construct_for_root_element<'dom>(
    context: &LayoutContext,
    root_element: impl NodeExt<'dom>,
) -> (ContainsFloats, Vec<ArcRefCell<BlockLevelBox>>) {
    let style = root_element.style(context);
    let box_style = style.get_box();

    let display_inside = match Display::from(box_style.display) {
        Display::None => return (ContainsFloats::No, Vec::new()),
        Display::Contents => {
            // Unreachable because the style crate adjusts the computed values:
            // https://drafts.csswg.org/css-display-3/#transformations
            // “'display' of 'contents' computes to 'block' on the root element”
            unreachable!()
        },
        // The root element is blockified, ignore DisplayOutside
        Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
    };

    let contents =
        ReplacedContent::for_element(root_element).map_or(Contents::OfElement, Contents::Replaced);
    if box_style.position.is_absolutely_positioned() {
        (
            ContainsFloats::No,
            vec![ArcRefCell::new(
                BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
                    AbsolutelyPositionedBox::construct(
                        context,
                        root_element,
                        style,
                        display_inside,
                        contents,
                    ),
                )),
            )],
        )
    } else if box_style.float.is_floating() {
        (
            ContainsFloats::Yes,
            vec![ArcRefCell::new(BlockLevelBox::OutOfFlowFloatBox(
                FloatBox::construct(context, root_element, style, display_inside, contents),
            ))],
        )
    } else {
        let propagated_text_decoration_line = style.clone_text_decoration_line();
        (
            ContainsFloats::No,
            vec![ArcRefCell::new(BlockLevelBox::Independent(
                IndependentFormattingContext::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                    ContentSizesRequest::None,
                    propagated_text_decoration_line,
                ),
            ))],
        )
    }
}

impl BoxTreeRoot {
    pub fn layout(
        &self,
        layout_context: &LayoutContext,
        viewport: euclid::Size2D<f32, CSSPixel>,
    ) -> FragmentTreeRoot {
        let style = ComputedValues::initial_values();

        // FIXME: use the document’s mode:
        // https://drafts.csswg.org/css-writing-modes/#principal-flow
        let physical_containing_block = PhysicalRect::new(
            PhysicalPoint::zero(),
            PhysicalSize::new(Length::new(viewport.width), Length::new(viewport.height)),
        );
        let initial_containing_block = DefiniteContainingBlock {
            size: Vec2 {
                inline: physical_containing_block.size.width,
                block: physical_containing_block.size.height,
            },
            style,
        };

        let dummy_tree_rank = 0;
        let mut positioning_context =
            PositioningContext::new_for_containing_block_for_all_descendants();
        let independent_layout = self.0.layout(
            layout_context,
            &mut positioning_context,
            &(&initial_containing_block).into(),
            dummy_tree_rank,
        );

        let mut children = independent_layout
            .fragments
            .into_iter()
            .map(|fragment| ArcRefCell::new(fragment))
            .collect();
        positioning_context.layout_initial_containing_block_children(
            layout_context,
            &initial_containing_block,
            &mut children,
        );

        let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
            let child_overflow = child
                .borrow()
                .scrollable_overflow(&physical_containing_block);

            // https://drafts.csswg.org/css-overflow/#scrolling-direction
            // We want to clip scrollable overflow on box-start and inline-start
            // sides of the scroll container.
            //
            // FIXME(mrobinson, bug 25564): This should take into account writing
            // mode.
            let child_overflow = PhysicalRect::new(
                euclid::Point2D::zero(),
                euclid::Size2D::new(
                    child_overflow.size.width + child_overflow.origin.x,
                    child_overflow.size.height + child_overflow.origin.y,
                ),
            );
            acc.union(&child_overflow)
        });

        FragmentTreeRoot {
            children,
            scrollable_overflow,
            initial_containing_block: physical_containing_block,
        }
    }
}

impl FragmentTreeRoot {
    pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
        let mut stacking_context = StackingContext::create_root(&builder.wr);
        {
            let mut stacking_context_builder = StackingContextBuilder::new(&mut builder.wr);
            let containing_block_info = ContainingBlockInfo {
                rect: self.initial_containing_block,
                nearest_containing_block: None,
                containing_block_for_all_descendants: ContainingBlock::new(
                    &self.initial_containing_block,
                    stacking_context_builder.current_space_and_clip,
                ),
            };

            for fragment in &self.children {
                fragment.borrow().build_stacking_context_tree(
                    fragment,
                    &mut stacking_context_builder,
                    &containing_block_info,
                    &mut stacking_context,
                    StackingContextBuildMode::SkipHoisted,
                );
            }
        }

        stacking_context.sort();
        stacking_context.build_display_list(builder);
    }

    pub fn print(&self) {
        let mut print_tree = PrintTree::new("Fragment Tree".to_string());
        for fragment in &self.children {
            fragment.borrow().print(&mut print_tree);
        }
    }

    pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
        webrender_api::units::LayoutSize::from_untyped(Size2D::new(
            self.scrollable_overflow.size.width.px(),
            self.scrollable_overflow.size.height.px(),
        ))
    }

    pub(crate) fn find<T>(
        &self,
        mut process_func: impl FnMut(&Fragment, &PhysicalRect<Length>) -> Option<T>,
    ) -> Option<T> {
        self.children.iter().find_map(|child| {
            child
                .borrow()
                .find(&self.initial_containing_block, &mut process_func)
        })
    }

    pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
        let mut bounding_box = PhysicalRect::zero();
        self.find(|fragment, containing_block| {
            if fragment.tag() != Some(requested_node) {
                return None::<()>;
            }

            let fragment_relative_rect = match fragment {
                Fragment::Box(fragment) => fragment
                    .border_rect()
                    .to_physical(fragment.style.writing_mode, &containing_block),
                Fragment::Text(fragment) => fragment
                    .rect
                    .to_physical(fragment.parent_style.writing_mode, &containing_block),
                Fragment::AbsoluteOrFixedPositioned(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return None,
            };

            bounding_box = fragment_relative_rect
                .translate(containing_block.origin.to_vector())
                .union(&bounding_box);
            None::<()>
        });

        Rect::new(
            Point2D::new(
                Au::from_f32_px(bounding_box.origin.x.px()),
                Au::from_f32_px(bounding_box.origin.y.px()),
            ),
            Size2D::new(
                Au::from_f32_px(bounding_box.size.width.px()),
                Au::from_f32_px(bounding_box.size.height.px()),
            ),
        )
    }

    pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
        self.find(|fragment, containing_block| {
            let (style, padding_rect) = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => {
                    (&fragment.style, fragment.padding_rect())
                },
                Fragment::AbsoluteOrFixedPositioned(_) |
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return None,
            };

            // https://drafts.csswg.org/cssom-view/#dom-element-clienttop
            // " If the element has no associated CSS layout box or if the
            //   CSS layout box is inline, return zero." For this check we
            // also explicitly ignore the list item portion of the display
            // style.
            let display = &style.get_box().display;
            if display.inside() == style::values::specified::box_::DisplayInside::Flow &&
                display.outside() == style::values::specified::box_::DisplayOutside::Inline
            {
                return Some(Rect::zero());
            }

            let padding_rect = padding_rect.to_physical(style.writing_mode, &containing_block);
            let border = style.get_border();
            Some(Rect::new(
                Point2D::new(
                    border.border_left_width.px() as i32,
                    border.border_top_width.px() as i32,
                ),
                Size2D::new(
                    padding_rect.size.width.px() as i32,
                    padding_rect.size.height.px() as i32,
                ),
            ))
        })
        .unwrap_or_else(Rect::zero)
    }
}
<commit_msg>Set in the DOM the box generated by the root element<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::display_list::stacking_context::{
    ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode,
    StackingContextBuilder,
};
use crate::dom_traversal::{Contents, NodeExt};
use crate::element_data::LayoutBox;
use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2;
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Display, DisplayGeneratingBox};
use crate::DefiniteContainingBlock;
use app_units::Au;
use euclid::default::{Point2D, Rect, Size2D};
use gfx_traits::print_tree::PrintTree;
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style_traits::CSSPixel;

#[derive(Serialize)]
pub struct BoxTreeRoot(BlockFormattingContext);

#[derive(Serialize)]
pub struct FragmentTreeRoot {
    /// The children of the root of the fragment tree.
    children: Vec<ArcRefCell<Fragment>>,

    /// The scrollable overflow of the root of the fragment tree.
    scrollable_overflow: PhysicalRect<Length>,

    /// The containing block used in the layout of this fragment tree.
    initial_containing_block: PhysicalRect<Length>,
}

impl BoxTreeRoot {
    pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
    where
        Node: 'dom + Copy + LayoutNode<'dom> + Send + Sync,
    {
        let (contains_floats, boxes) = construct_for_root_element(&context, root_element);

        // Zero box for `:root { display: none }`, one for the root element otherwise.
        assert!(boxes.len() <= 1);

        Self(BlockFormattingContext {
            contains_floats: contains_floats == ContainsFloats::Yes,
            contents: BlockContainer::BlockLevelBoxes(boxes),
        })
    }
}

fn construct_for_root_element<'dom>(
    context: &LayoutContext,
    root_element: impl NodeExt<'dom>,
) -> (ContainsFloats, Vec<ArcRefCell<BlockLevelBox>>) {
    let style = root_element.style(context);
    let box_style = style.get_box();

    let display_inside = match Display::from(box_style.display) {
        Display::None => {
            root_element.unset_boxes_in_subtree();
            return (ContainsFloats::No, Vec::new());
        },
        Display::Contents => {
            // Unreachable because the style crate adjusts the computed values:
            // https://drafts.csswg.org/css-display-3/#transformations
            // “'display' of 'contents' computes to 'block' on the root element”
            unreachable!()
        },
        // The root element is blockified, ignore DisplayOutside
        Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { inside, .. }) => inside,
    };

    let contents =
        ReplacedContent::for_element(root_element).map_or(Contents::OfElement, Contents::Replaced);
    let (contains_floats, root_box) = if box_style.position.is_absolutely_positioned() {
        (
            ContainsFloats::No,
            BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(Arc::new(
                AbsolutelyPositionedBox::construct(
                    context,
                    root_element,
                    style,
                    display_inside,
                    contents,
                ),
            )),
        )
    } else if box_style.float.is_floating() {
        (
            ContainsFloats::Yes,
            BlockLevelBox::OutOfFlowFloatBox(FloatBox::construct(
                context,
                root_element,
                style,
                display_inside,
                contents,
            )),
        )
    } else {
        let propagated_text_decoration_line = style.clone_text_decoration_line();
        (
            ContainsFloats::No,
            BlockLevelBox::Independent(IndependentFormattingContext::construct(
                context,
                root_element,
                style,
                display_inside,
                contents,
                ContentSizesRequest::None,
                propagated_text_decoration_line,
            )),
        )
    };
    let root_box = ArcRefCell::new(root_box);
    root_element
        .element_box_slot()
        .set(LayoutBox::BlockLevel(root_box.clone()));
    (contains_floats, vec![root_box])
}

impl BoxTreeRoot {
    pub fn layout(
        &self,
        layout_context: &LayoutContext,
        viewport: euclid::Size2D<f32, CSSPixel>,
    ) -> FragmentTreeRoot {
        let style = ComputedValues::initial_values();

        // FIXME: use the document’s mode:
        // https://drafts.csswg.org/css-writing-modes/#principal-flow
        let physical_containing_block = PhysicalRect::new(
            PhysicalPoint::zero(),
            PhysicalSize::new(Length::new(viewport.width), Length::new(viewport.height)),
        );
        let initial_containing_block = DefiniteContainingBlock {
            size: Vec2 {
                inline: physical_containing_block.size.width,
                block: physical_containing_block.size.height,
            },
            style,
        };

        let dummy_tree_rank = 0;
        let mut positioning_context =
            PositioningContext::new_for_containing_block_for_all_descendants();
        let independent_layout = self.0.layout(
            layout_context,
            &mut positioning_context,
            &(&initial_containing_block).into(),
            dummy_tree_rank,
        );

        let mut children = independent_layout
            .fragments
            .into_iter()
            .map(|fragment| ArcRefCell::new(fragment))
            .collect::<Vec<_>>();

        // Zero box for `:root { display: none }`, one for the root element otherwise.
        assert!(children.len() <= 1);

        // There may be more fragments at the top-level
        // (for positioned boxes whose containing is the initial containing block)
        // but only if there was one fragment for the root element.
        positioning_context.layout_initial_containing_block_children(
            layout_context,
            &initial_containing_block,
            &mut children,
        );

        let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
            let child_overflow = child
                .borrow()
                .scrollable_overflow(&physical_containing_block);

            // https://drafts.csswg.org/css-overflow/#scrolling-direction
            // We want to clip scrollable overflow on box-start and inline-start
            // sides of the scroll container.
            //
            // FIXME(mrobinson, bug 25564): This should take into account writing
            // mode.
            let child_overflow = PhysicalRect::new(
                euclid::Point2D::zero(),
                euclid::Size2D::new(
                    child_overflow.size.width + child_overflow.origin.x,
                    child_overflow.size.height + child_overflow.origin.y,
                ),
            );
            acc.union(&child_overflow)
        });

        FragmentTreeRoot {
            children,
            scrollable_overflow,
            initial_containing_block: physical_containing_block,
        }
    }
}

impl FragmentTreeRoot {
    pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
        let mut stacking_context = StackingContext::create_root(&builder.wr);
        {
            let mut stacking_context_builder = StackingContextBuilder::new(&mut builder.wr);
            let containing_block_info = ContainingBlockInfo {
                rect: self.initial_containing_block,
                nearest_containing_block: None,
                containing_block_for_all_descendants: ContainingBlock::new(
                    &self.initial_containing_block,
                    stacking_context_builder.current_space_and_clip,
                ),
            };

            for fragment in &self.children {
                fragment.borrow().build_stacking_context_tree(
                    fragment,
                    &mut stacking_context_builder,
                    &containing_block_info,
                    &mut stacking_context,
                    StackingContextBuildMode::SkipHoisted,
                );
            }
        }

        stacking_context.sort();
        stacking_context.build_display_list(builder);
    }

    pub fn print(&self) {
        let mut print_tree = PrintTree::new("Fragment Tree".to_string());
        for fragment in &self.children {
            fragment.borrow().print(&mut print_tree);
        }
    }

    pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
        webrender_api::units::LayoutSize::from_untyped(Size2D::new(
            self.scrollable_overflow.size.width.px(),
            self.scrollable_overflow.size.height.px(),
        ))
    }

    pub(crate) fn find<T>(
        &self,
        mut process_func: impl FnMut(&Fragment, &PhysicalRect<Length>) -> Option<T>,
    ) -> Option<T> {
        self.children.iter().find_map(|child| {
            child
                .borrow()
                .find(&self.initial_containing_block, &mut process_func)
        })
    }

    pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
        let mut bounding_box = PhysicalRect::zero();
        self.find(|fragment, containing_block| {
            if fragment.tag() != Some(requested_node) {
                return None::<()>;
            }

            let fragment_relative_rect = match fragment {
                Fragment::Box(fragment) => fragment
                    .border_rect()
                    .to_physical(fragment.style.writing_mode, &containing_block),
                Fragment::Text(fragment) => fragment
                    .rect
                    .to_physical(fragment.parent_style.writing_mode, &containing_block),
                Fragment::AbsoluteOrFixedPositioned(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return None,
            };

            bounding_box = fragment_relative_rect
                .translate(containing_block.origin.to_vector())
                .union(&bounding_box);
            None::<()>
        });

        Rect::new(
            Point2D::new(
                Au::from_f32_px(bounding_box.origin.x.px()),
                Au::from_f32_px(bounding_box.origin.y.px()),
            ),
            Size2D::new(
                Au::from_f32_px(bounding_box.size.width.px()),
                Au::from_f32_px(bounding_box.size.height.px()),
            ),
        )
    }

    pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
        self.find(|fragment, containing_block| {
            let (style, padding_rect) = match fragment {
                Fragment::Box(fragment) if fragment.tag == requested_node => {
                    (&fragment.style, fragment.padding_rect())
                },
                Fragment::AbsoluteOrFixedPositioned(_) |
                Fragment::Box(_) |
                Fragment::Text(_) |
                Fragment::Image(_) |
                Fragment::Anonymous(_) => return None,
            };

            // https://drafts.csswg.org/cssom-view/#dom-element-clienttop
            // " If the element has no associated CSS layout box or if the
            //   CSS layout box is inline, return zero." For this check we
            // also explicitly ignore the list item portion of the display
            // style.
            let display = &style.get_box().display;
            if display.inside() == style::values::specified::box_::DisplayInside::Flow &&
                display.outside() == style::values::specified::box_::DisplayOutside::Inline
            {
                return Some(Rect::zero());
            }

            let padding_rect = padding_rect.to_physical(style.writing_mode, &containing_block);
            let border = style.get_border();
            Some(Rect::new(
                Point2D::new(
                    border.border_left_width.px() as i32,
                    border.border_top_width.px() as i32,
                ),
                Size2D::new(
                    padding_rect.size.width.px() as i32,
                    padding_rect.size.height.px() as i32,
                ),
            ))
        })
        .unwrap_or_else(Rect::zero)
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "cmake_build")]
extern crate cmake;
extern crate num_cpus;
extern crate pkg_config;

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

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn run_command_or_fail<P>(dir: &str, cmd: P, args: &[&str])
where
    P: AsRef<Path>,
{
    let cmd = cmd.as_ref();
    let cmd = if cmd.components().count() > 1 && cmd.is_relative() {
        // If `cmd` is a relative path (and not a bare command that should be
        // looked up in PATH), absolutize it relative to `dir`, as otherwise the
        // behavior of std::process::Command is undefined.
        // https://github.com/rust-lang/rust/issues/37868
        PathBuf::from(dir)
            .join(cmd)
            .canonicalize()
            .expect("canonicalization failed")
    } else {
        PathBuf::from(cmd)
    };
    println_stderr!(
        "Running command: \"{} {}\" in dir: {}",
        cmd.display(),
        args.join(" "),
        dir
    );
    let ret = Command::new(cmd).current_dir(dir).args(args).status();
    match ret.map(|status| (status.success(), status.code())) {
        Ok((true, _)) => return,
        Ok((false, Some(c))) => panic!("Command failed with error code {}", c),
        Ok((false, None)) => panic!("Command got killed"),
        Err(e) => panic!("Command failed with error: {}", e),
    }
}

fn main() {
    let librdkafka_version = env!("CARGO_PKG_VERSION")
        .split('-')
        .next()
        .expect("Crate version is not valid");

    if env::var("CARGO_FEATURE_DYNAMIC_LINKING").is_ok() {
        println_stderr!("librdkafka will be linked dynamically");
        let pkg_probe = pkg_config::Config::new()
            .cargo_metadata(true)
            .atleast_version(librdkafka_version)
            .probe("rdkafka");

        match pkg_probe {
            Ok(library) => {
                println_stderr!("librdkafka found on the system:");
                println_stderr!("  Name: {:?}", library.libs);
                println_stderr!("  Path: {:?}", library.link_paths);
                println_stderr!("  Version: {}", library.version);
            }
            Err(_) => {
                println_stderr!(
                    "librdkafka {} cannot be found on the system",
                    librdkafka_version
                );
                println_stderr!("Dynamic linking failed. Exiting.");
                process::exit(1);
            }
        }
    } else {
        if !Path::new("librdkafka/LICENSE").exists() {
            println_stderr!("Setting up submodules");
            run_command_or_fail("../", "git", &["submodule", "update", "--init"]);
        }
        println_stderr!("Building and linking librdkafka statically");
        build_librdkafka();
    }

    let bindings = bindgen::Builder::default()
        .header("librdkafka/src/rdkafka.h")
        .generate_comments(false)
        .emit_builtins()
        // TODO: using rustified_enum is somewhat dangerous, especially when
        // also using shared libraries.
        // For details: https://github.com/rust-lang/rust-bindgen/issues/758
        .rustified_enum("rd_kafka_vtype_t")
        .rustified_enum("rd_kafka_type_t")
        .rustified_enum("rd_kafka_conf_res_t")
        .rustified_enum("rd_kafka_resp_err_t")
        .rustified_enum("rd_kafka_timestamp_type_t")
        .rustified_enum("rd_kafka_admin_op_t")
        .rustified_enum("rd_kafka_ResourceType_t")
        .rustified_enum("rd_kafka_ConfigSource_t")
        .generate()
        .expect("failed to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("failed to write bindings");
}

#[cfg(not(feature = "cmake_build"))]
fn build_librdkafka() {
    let mut configure_flags = Vec::new();

    if env::var("CARGO_FEATURE_SASL").is_ok() {
        configure_flags.push("--enable-sasl");
        println!("cargo:rustc-link-lib=sasl2");
    } else {
        configure_flags.push("--disable-sasl");
    }

    if env::var("CARGO_FEATURE_SSL").is_ok() {
        configure_flags.push("--enable-ssl");
    } else {
        configure_flags.push("--disable-ssl");
    }

    if env::var("CARGO_FEATURE_ZSTD").is_ok() {
        configure_flags.push("--enable-zstd");
        println!("cargo:rustc-link-lib=static=zstd");
    } else {
        configure_flags.push("--disable-zstd");
    }

    if env::var("CARGO_FEATURE_EXTERNAL_LZ4").is_ok() {
        configure_flags.push("--enable-lz4");
        println!("cargo:rustc-link-lib=static=lz4");
    } else {
        configure_flags.push("--disable-lz4");
    }

    println!("Configuring librdkafka");
    run_command_or_fail("librdkafka", "./configure", configure_flags.as_slice());

    println!("Compiling librdkafka");
    make_librdkafka();

    println!(
        "cargo:rustc-link-search=native={}/librdkafka/src",
        env::current_dir()
            .expect("Can't find current dir")
            .display()
    );
    println!("cargo:rustc-link-lib=static=rdkafka");
}

#[cfg(not(feature = "cmake_build"))]
fn make_librdkafka() {
    run_command_or_fail(
        "librdkafka",
        if cfg!(target_os = "freebsd") { "gmake" } else { "make" },
        &["-j", &num_cpus::get().to_string(), "libs"],
    );
}

#[cfg(feature = "cmake_build")]
fn build_librdkafka() {
    env::set_var("NUM_JOBS", num_cpus::get().to_string());
    let mut config = cmake::Config::new("librdkafka");
    config
        .define("RDKAFKA_BUILD_STATIC", "1")
        .build_target("rdkafka");
    if env::var("CARGO_FEATURE_SSL").is_ok() {
        config.define("WITH_SSL", "1");
    } else {
        config.define("WITH_SSL", "0");
    }
    if env::var("CARGO_FEATURE_SASL").is_ok() {
        config.define("WITH_SASL", "1");
    } else {
        config.define("WITH_SASL", "0");
    }
    if env::var("CARGO_FEATURE_ZSTD").is_ok() {
        config.define("WITH_ZSTD", "1");
        config.register_dep("zstd");
        println!("cargo:rustc-link-lib=static=zstd");
    } else {
        config.define("WITH_ZSTD", "0");
    }
    if env::var("CARGO_FEATURE_EXTERNAL_LZ4").is_ok() {
        config.define("ENABLE_LZ4_EXT", "1");
        println!("cargo:rustc-link-lib=static=lz4");
    } else {
        config.define("ENABLE_LZ4_EXT", "0");
    }
    if let Ok(system_name) = env::var("CMAKE_SYSTEM_NAME") {
        config.define("CMAKE_SYSTEM_NAME", system_name);
    }
    let dst = config.build();
    println!("cargo:rustc-link-search=native={}/build/src", dst.display());
    println!("cargo:rustc-link-lib=static=rdkafka");
}
<commit_msg>Use eprintln! instead of custom macro<commit_after>#[cfg(feature = "cmake_build")]
extern crate cmake;
extern crate num_cpus;
extern crate pkg_config;

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

fn run_command_or_fail<P>(dir: &str, cmd: P, args: &[&str])
where
    P: AsRef<Path>,
{
    let cmd = cmd.as_ref();
    let cmd = if cmd.components().count() > 1 && cmd.is_relative() {
        // If `cmd` is a relative path (and not a bare command that should be
        // looked up in PATH), absolutize it relative to `dir`, as otherwise the
        // behavior of std::process::Command is undefined.
        // https://github.com/rust-lang/rust/issues/37868
        PathBuf::from(dir)
            .join(cmd)
            .canonicalize()
            .expect("canonicalization failed")
    } else {
        PathBuf::from(cmd)
    };
    eprintln!(
        "Running command: \"{} {}\" in dir: {}",
        cmd.display(),
        args.join(" "),
        dir
    );
    let ret = Command::new(cmd).current_dir(dir).args(args).status();
    match ret.map(|status| (status.success(), status.code())) {
        Ok((true, _)) => return,
        Ok((false, Some(c))) => panic!("Command failed with error code {}", c),
        Ok((false, None)) => panic!("Command got killed"),
        Err(e) => panic!("Command failed with error: {}", e),
    }
}

fn main() {
    let librdkafka_version = env!("CARGO_PKG_VERSION")
        .split('-')
        .next()
        .expect("Crate version is not valid");

    if env::var("CARGO_FEATURE_DYNAMIC_LINKING").is_ok() {
        eprintln!("librdkafka will be linked dynamically");
        let pkg_probe = pkg_config::Config::new()
            .cargo_metadata(true)
            .atleast_version(librdkafka_version)
            .probe("rdkafka");

        match pkg_probe {
            Ok(library) => {
                eprintln!("librdkafka found on the system:");
                eprintln!("  Name: {:?}", library.libs);
                eprintln!("  Path: {:?}", library.link_paths);
                eprintln!("  Version: {}", library.version);
            }
            Err(_) => {
                eprintln!(
                    "librdkafka {} cannot be found on the system",
                    librdkafka_version
                );
                eprintln!("Dynamic linking failed. Exiting.");
                process::exit(1);
            }
        }
    } else {
        if !Path::new("librdkafka/LICENSE").exists() {
            eprintln!("Setting up submodules");
            run_command_or_fail("../", "git", &["submodule", "update", "--init"]);
        }
        eprintln!("Building and linking librdkafka statically");
        build_librdkafka();
    }

    let bindings = bindgen::Builder::default()
        .header("librdkafka/src/rdkafka.h")
        .generate_comments(false)
        .emit_builtins()
        // TODO: using rustified_enum is somewhat dangerous, especially when
        // also using shared libraries.
        // For details: https://github.com/rust-lang/rust-bindgen/issues/758
        .rustified_enum("rd_kafka_vtype_t")
        .rustified_enum("rd_kafka_type_t")
        .rustified_enum("rd_kafka_conf_res_t")
        .rustified_enum("rd_kafka_resp_err_t")
        .rustified_enum("rd_kafka_timestamp_type_t")
        .rustified_enum("rd_kafka_admin_op_t")
        .rustified_enum("rd_kafka_ResourceType_t")
        .rustified_enum("rd_kafka_ConfigSource_t")
        .generate()
        .expect("failed to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("failed to write bindings");
}

#[cfg(not(feature = "cmake_build"))]
fn build_librdkafka() {
    let mut configure_flags = Vec::new();

    if env::var("CARGO_FEATURE_SASL").is_ok() {
        configure_flags.push("--enable-sasl");
        println!("cargo:rustc-link-lib=sasl2");
    } else {
        configure_flags.push("--disable-sasl");
    }

    if env::var("CARGO_FEATURE_SSL").is_ok() {
        configure_flags.push("--enable-ssl");
    } else {
        configure_flags.push("--disable-ssl");
    }

    if env::var("CARGO_FEATURE_ZSTD").is_ok() {
        configure_flags.push("--enable-zstd");
        println!("cargo:rustc-link-lib=static=zstd");
    } else {
        configure_flags.push("--disable-zstd");
    }

    if env::var("CARGO_FEATURE_EXTERNAL_LZ4").is_ok() {
        configure_flags.push("--enable-lz4");
        println!("cargo:rustc-link-lib=static=lz4");
    } else {
        configure_flags.push("--disable-lz4");
    }

    println!("Configuring librdkafka");
    run_command_or_fail("librdkafka", "./configure", configure_flags.as_slice());

    println!("Compiling librdkafka");
    make_librdkafka();

    println!(
        "cargo:rustc-link-search=native={}/librdkafka/src",
        env::current_dir()
            .expect("Can't find current dir")
            .display()
    );
    println!("cargo:rustc-link-lib=static=rdkafka");
}

#[cfg(not(feature = "cmake_build"))]
fn make_librdkafka() {
    run_command_or_fail(
        "librdkafka",
        if cfg!(target_os = "freebsd") { "gmake" } else { "make" },
        &["-j", &num_cpus::get().to_string(), "libs"],
    );
}

#[cfg(feature = "cmake_build")]
fn build_librdkafka() {
    env::set_var("NUM_JOBS", num_cpus::get().to_string());
    let mut config = cmake::Config::new("librdkafka");
    config
        .define("RDKAFKA_BUILD_STATIC", "1")
        .build_target("rdkafka");
    if env::var("CARGO_FEATURE_SSL").is_ok() {
        config.define("WITH_SSL", "1");
    } else {
        config.define("WITH_SSL", "0");
    }
    if env::var("CARGO_FEATURE_SASL").is_ok() {
        config.define("WITH_SASL", "1");
    } else {
        config.define("WITH_SASL", "0");
    }
    if env::var("CARGO_FEATURE_ZSTD").is_ok() {
        config.define("WITH_ZSTD", "1");
        config.register_dep("zstd");
        println!("cargo:rustc-link-lib=static=zstd");
    } else {
        config.define("WITH_ZSTD", "0");
    }
    if env::var("CARGO_FEATURE_EXTERNAL_LZ4").is_ok() {
        config.define("ENABLE_LZ4_EXT", "1");
        println!("cargo:rustc-link-lib=static=lz4");
    } else {
        config.define("ENABLE_LZ4_EXT", "0");
    }
    if let Ok(system_name) = env::var("CMAKE_SYSTEM_NAME") {
        config.define("CMAKE_SYSTEM_NAME", system_name);
    }
    let dst = config.build();
    println!("cargo:rustc-link-search=native={}/build/src", dst.display());
    println!("cargo:rustc-link-lib=static=rdkafka");
}
<|endoftext|>