<commit_before>//! Path summaries that are either child local, or leave the scope and re-enter from the parent.

use std::cmp::Ordering;
use std::default::Default;
use std::fmt::{Display, Formatter};
use std::fmt::Error;

use progress::{Timestamp, PathSummary};
use progress::nested::product::Product;
use progress::nested::summary::Summary::{Local, Outer};

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Summary<S, T> {
    Local(T),    // reachable within inner scope.
    Outer(S, T), // unreachable within scope, reachable through outer scope and then inner.
}

impl<S, T: Default> Default for Summary<S, T> {
    fn default() -> Summary<S, T> { Local(Default::default()) }
}

impl<S:PartialOrd+Copy, T:PartialOrd+Copy> PartialOrd for Summary<S, T> {
    #[inline]
    fn partial_cmp(&self, other: &Summary<S, T>) -> Option<Ordering> {
        match (*self, *other) {
            (Local(t1),    Local(t2))    => t1.partial_cmp(&t2),
            (Local(t1),    Outer(_,t2))  => match t1.partial_cmp(&t2) {
                Some(Ordering::Less)    => Some(Ordering::Less), // TODO : Is this correct?
                Some(Ordering::Equal)   => Some(Ordering::Less), // might not be strict if s2~=0, but lets break ties
                Some(Ordering::Greater) => None,                 // if s2 = 0 we could be leaving something else out
                None                    => None,
            },
            (Outer(s1,t1), Outer(s2,t2)) => (s1,t1).partial_cmp(&(s2,t2)),
            (Outer(_,t1),   Local(t2))   => match t1.partial_cmp(&t2) {
                Some(Ordering::Less)    => None,
                Some(Ordering::Equal)   => Some(Ordering::Greater), // might not be strict if s2~=0, but lets break ties
                Some(Ordering::Greater) => Some(Ordering::Greater), // if s2 = 0 we could be leaving something else out
                None                    => None,
            },
        }
    }
}

impl<TOuter, SOuter, TInner, SInner> PathSummary<Product<TOuter, TInner>> for Summary<SOuter, SInner>
where TOuter: Timestamp,
      TInner: Timestamp,
      SOuter: PathSummary<TOuter>,
      SInner: PathSummary<TInner>,
{
    // this makes sense for a total order, but less clear for a partial order.
    #[inline]
    fn results_in(&self, product: &Product<TOuter, TInner>) -> Product<TOuter, TInner> {
        match *self {
            Local(ref iters)              => Product::new(product.outer.clone(), iters.results_in(&product.inner)),
            Outer(ref summary, ref iters) => Product::new(summary.results_in(&product.outer), iters.results_in(&Default::default())),
        }
    }
    #[inline]
    fn followed_by(&self, other: &Summary<SOuter, SInner>) -> Summary<SOuter, SInner> {
        match (*self, *other) {
            (Local(inner1), Local(inner2))             => Local(inner1.followed_by(&inner2)),
            (Local(_), Outer(_, _))                    => *other,
            (Outer(outer1, inner1), Local(inner2))     => Outer(outer1, inner1.followed_by(&inner2)),
            (Outer(outer1, _), Outer(outer2, inner2))  => Outer(outer1.followed_by(&outer2), inner2),
        }
    }
}

impl<SOuter: Display, SInner: Display> Display for Summary<SOuter, SInner> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match self {
            &Local(ref s) => f.write_str(&format!("Local({})", s)),
            &Outer(ref s, ref t) => f.write_str(&format!("Outer({}, {})", s, t))
        }
    }
}
<commit_msg>added likely more correct summary reasoning<commit_after>//! Path summaries that are either child local, or leave the scope and re-enter from the parent.

use std::cmp::Ordering;
use std::default::Default;
use std::fmt::{Display, Formatter};
use std::fmt::Error;

use progress::{Timestamp, PathSummary};
use progress::nested::product::Product;
use progress::nested::summary::Summary::{Local, Outer};

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Summary<S, T> {
    Local(T),    // reachable within inner scope.
    Outer(S, T), // unreachable within scope, reachable through outer scope and then inner.
}

impl<S, T: Default> Default for Summary<S, T> {
    fn default() -> Summary<S, T> { Local(Default::default()) }
}

impl<S:PartialOrd+Copy, T:PartialOrd+Copy> PartialOrd for Summary<S, T> {
    #[inline]
    fn partial_cmp(&self, other: &Summary<S, T>) -> Option<Ordering> {
        // Two summaries are comparable if they are of the same type (Local, Outer).
        // Otherwise, as Local *updates* and Outer *sets* the inner coordinate, we
        // cannot be sure that either strictly improves on the other.
        match (*self, *other) {
            (Local(t1),    Local(t2))    => t1.partial_cmp(&t2),
            (Local(_),     Outer(_,_))   => None,
            (Outer(s1,t1), Outer(s2,t2)) => (s1,t1).partial_cmp(&(s2,t2)),
            (Outer(_,_),   Local(_))     => None,
        }
    }
}

impl<TOuter, SOuter, TInner, SInner> PathSummary<Product<TOuter, TInner>> for Summary<SOuter, SInner>
where TOuter: Timestamp,
      TInner: Timestamp,
      SOuter: PathSummary<TOuter>,
      SInner: PathSummary<TInner>,
{
    // this makes sense for a total order, but less clear for a partial order.
    #[inline]
    fn results_in(&self, product: &Product<TOuter, TInner>) -> Product<TOuter, TInner> {
        match *self {
            Local(ref iters)              => Product::new(product.outer.clone(), iters.results_in(&product.inner)),
            Outer(ref summary, ref iters) => Product::new(summary.results_in(&product.outer), iters.results_in(&Default::default())),
        }
    }
    #[inline]
    fn followed_by(&self, other: &Summary<SOuter, SInner>) -> Summary<SOuter, SInner> {
        match (*self, *other) {
            (Local(inner1), Local(inner2))             => Local(inner1.followed_by(&inner2)),
            (Local(_), Outer(_, _))                    => *other,
            (Outer(outer1, inner1), Local(inner2))     => Outer(outer1, inner1.followed_by(&inner2)),
            (Outer(outer1, _), Outer(outer2, inner2))  => Outer(outer1.followed_by(&outer2), inner2),
        }
    }
}

impl<SOuter: Display, SInner: Display> Display for Summary<SOuter, SInner> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match self {
            &Local(ref s) => f.write_str(&format!("Local({})", s)),
            &Outer(ref s, ref t) => f.write_str(&format!("Outer({}, {})", s, t))
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate prodbg_api;
extern crate gdb_remote;
extern crate libc;
use prodbg_api::*;
use libc::c_void;
use gdb_remote::GdbRemote;

struct AmigaUaeBackend {
    capstone: Capstone,
    conn: GdbRemote,
    exception_location: u32,
}

impl AmigaUaeBackend {
    fn get_u32(data: &[u8]) -> u32 {
        let t0 = data[0] as u32;
        let t1 = data[1] as u32;
        let t2 = data[2] as u32;
        let t3 = data[3] as u32;
        (t0 << 24) | (t1 << 16) | (t2 << 8) | t3
    }

    fn write_register(writer: &mut Writer, name: &str, data: u32, read_only: bool) {
        writer.array_entry_begin();
        writer.write_string("name", name);
        writer.write_u8("size", 4);

        if read_only {
            writer.write_u8("read_only", 1);
        }

        writer.write_u32("register", data);

        writer.array_entry_end();
    }

    fn write_registers(&mut self, writer: &mut Writer, data: &[u8]) {
        let mut index = 0;

        writer.event_begin(EventType::SetRegisters as u16);
        writer.array_begin("registers");

        // d registers

        for i in 0..8 {
            let name = format!("d{}", i);
            let reg = Self::get_u32(&data[index..]);
            Self::write_register(writer, &name, reg, false);
            index += 4;
        }

        // a registers

        for i in 0..8 {
            let name = format!("a{}", i);
            let reg = Self::get_u32(&data[index..]);
            Self::write_register(writer, &name, reg, false);
            index += 4;
        }

        // Status registers & pc

        let sr = Self::get_u32(&data[index..]);
        let pc = Self::get_u32(&data[index + 4..]);

        self.exception_location = pc;

        Self::write_register(writer, "sr", sr, true);
        Self::write_register(writer, "pc", pc, true);

        writer.array_end();
        writer.event_end();
    }

    fn write_disassembly(&mut self, reader: &mut Reader, writer: &mut Writer) {
        match self.capstone.open(Arch::M68K, CS_MODE_M68K_000) {
            Err(e) => {
                println!("Unable to open Capstone {}", e as i32);
                return;
            }
            _ => (),
        }

        let address = reader.find_u64("address_start").ok().unwrap();
        let count = reader.find_u32("instruction_count").ok().unwrap();

        let mut data = Vec::<u8>::with_capacity(256 * 1024);
        let memory_fetch_size = count * 4;

        if self.conn.get_memory(&mut data, address, memory_fetch_size as u64).is_err() {
            println!("Unable to fetch memory from {:x} - size {}", address, memory_fetch_size);
            return;
        }

        println!("disasm data address {:x} - len {}", address, data.len());

        if let Ok(insns) = self.capstone.disasm(&data, address as u64, 0) {
            writer.event_begin(EventType::SetDisassembly as u16);
            writer.array_begin("disassembly");
            let mut c = 0;

            for i in insns.iter() {
                let text = format!("{0: <10} {1: <10}", i.mnemonic().unwrap(), i.op_str().unwrap_or(""));
                writer.array_entry_begin();
                writer.write_u32("address", i.address as u32);
                writer.write_string("line", &text);
                writer.array_entry_end();
                c += 1;
            }

            println!("reported {} instructions", c);

            writer.array_end();
            writer.event_end();
        } else {
            println!("No instructions :(");
        }
    }

    fn get_memory(&mut self, reader: &mut Reader, writer: &mut Writer) {
        let mut data = Vec::<u8>::with_capacity(256 * 1024);

        let address = reader.find_u64("address_start").ok().unwrap();
        let size = reader.find_u32("size").ok().unwrap();

        if self.conn.get_memory(&mut data, address, size as u64).is_err() {
            println!("Unable to fetch memory from {:x} - size {}", address, size);
            return;
        }

        writer.event_begin(EventType::SetMemory as u16);
        writer.write_u64("address", address);
        writer.write_data("data", &data);
        writer.event_end();
    }

    fn write_exception_location(&mut self, writer: &mut Writer) {
        writer.event_begin(EventType::SetExceptionLocation as u16);
        writer.write_u64("address", self.exception_location as u64);
        writer.write_u8("size", 4);
        writer.event_end();
    }
}

impl Backend for AmigaUaeBackend {
    fn new(service: &Service) -> Self {
        AmigaUaeBackend {
            capstone: service.get_capstone(),
            conn: GdbRemote::new(),
            exception_location: 0,
        }
    }

    fn update(&mut self, action: i32, reader: &mut Reader, writer: &mut Writer) {
        for event in reader.get_event() {
            match event {
                EVENT_MENU_EVENT => {
                    if self.conn.connect("127.0.0.1:6860").is_ok() {
                        if self.conn.request_no_ack_mode().is_ok() {
                            println!("Connected. Ready to go!");
                        } else {
                            println!("no ack request failed");
                        }
                    } else {
                        println!("Unable to connect to UAE");
                    }
                }
                EVENT_GET_DISASSEMBLY => {
                    self.write_disassembly(reader, writer);
                }

                EVENT_GET_MEMORY => {
                    self.get_memory(reader, writer);
                }

                _ => (),
            }
        }

        match action {
            ACTION_BREAK => {
                println!("Break");
            }

            ACTION_STEP => {
                let mut step_res = [0; 16];
                let mut register_data = [0; 1024];
                self.conn.step(&mut step_res).unwrap();

                    println!("steping ok!");
                    if self.conn.get_registers(&mut register_data).is_ok() {
                        println!("setting registers!");
                        self.write_registers(writer, &register_data);
                    }

                self.write_exception_location(writer);
            }
            _ => (),
        }
    }

    fn register_menu(&mut self, menu_funcs: &mut MenuFuncs) -> *mut c_void {
        let menu = menu_funcs.create_menu("Amiga UAE Debugger");
        menu_funcs.add_menu_item(menu, "Connect to UAE...", 0, 0, 0);
        menu
    }
}

#[no_mangle]
pub fn init_plugin(plugin_handler: &mut PluginHandler) {
    define_backend_plugin!(PLUGIN, b"Amiga UAE Debugger\0", AmigaUaeBackend);
    plugin_handler.register_backend(&PLUGIN);
}

<commit_msg>Test code to write out info<commit_after>#[macro_use]
extern crate prodbg_api;
extern crate gdb_remote;
extern crate libc;
use prodbg_api::*;
use libc::c_void;
use gdb_remote::GdbRemote;

struct AmigaUaeBackend {
    capstone: Capstone,
    conn: GdbRemote,
    exception_location: u32,
}

impl AmigaUaeBackend {
    fn get_u32(data: &[u8]) -> u32 {
        let t0 = data[0] as u32;
        let t1 = data[1] as u32;
        let t2 = data[2] as u32;
        let t3 = data[3] as u32;
        (t0 << 24) | (t1 << 16) | (t2 << 8) | t3
    }

    fn write_register(writer: &mut Writer, name: &str, data: u32, read_only: bool) {
        writer.array_entry_begin();
        writer.write_string("name", name);
        writer.write_u8("size", 4);

        if read_only {
            writer.write_u8("read_only", 1);
        }

        writer.write_u32("register", data);

        writer.array_entry_end();
    }

    fn write_registers(&mut self, writer: &mut Writer, data: &[u8]) {
        let mut index = 0;

        writer.event_begin(EventType::SetRegisters as u16);
        writer.array_begin("registers");

        // d registers

        for i in 0..8 {
            let name = format!("d{}", i);
            let reg = Self::get_u32(&data[index..]);
            Self::write_register(writer, &name, reg, false);
            index += 4;
        }

        // a registers

        for i in 0..8 {
            let name = format!("a{}", i);
            let reg = Self::get_u32(&data[index..]);
            Self::write_register(writer, &name, reg, false);
            index += 4;
        }

        // Status registers & pc

        let sr = Self::get_u32(&data[index..]);
        let pc = Self::get_u32(&data[index + 4..]);

        self.exception_location = pc;

        Self::write_register(writer, "sr", sr, true);
        Self::write_register(writer, "pc", pc, true);

        writer.array_end();
        writer.event_end();
    }

    fn write_disassembly(&mut self, reader: &mut Reader, writer: &mut Writer) {
        match self.capstone.open(Arch::M68K, CS_MODE_M68K_000) {
            Err(e) => {
                println!("Unable to open Capstone {}", e as i32);
                return;
            }
            _ => (),
        }

        let address = reader.find_u64("address_start").ok().unwrap();
        let count = reader.find_u32("instruction_count").ok().unwrap();

        let mut data = Vec::<u8>::with_capacity(256 * 1024);
        let memory_fetch_size = count * 4;

        if self.conn.get_memory(&mut data, address, memory_fetch_size as u64).is_err() {
            println!("Unable to fetch memory from {:x} - size {}", address, memory_fetch_size);
            return;
        }

        println!("disasm data address {:x} - len {}", address, data.len());

        if let Ok(insns) = self.capstone.disasm(&data, address as u64, 0) {
            writer.event_begin(EventType::SetDisassembly as u16);
            writer.array_begin("disassembly");
            let mut c = 0;

            for i in insns.iter() {
                let text = format!("{0: <10} {1: <10}", i.mnemonic().unwrap(), i.op_str().unwrap_or(""));
                writer.array_entry_begin();
                writer.write_u32("address", i.address as u32);
                writer.write_string("line", &text);
                writer.array_entry_end();

                /*
                println!("{}", text);

                for register in i.regs_read().unwrap() {
                    let reg_name = self.capstone.reg_name(*register);
                    println!("read read {}", reg_name);
                }
                */

                c += 1;
            }

            println!("reported {} instructions", c);

            writer.array_end();
            writer.event_end();
        } else {
            println!("No instructions :(");
        }
    }

    fn get_memory(&mut self, reader: &mut Reader, writer: &mut Writer) {
        let mut data = Vec::<u8>::with_capacity(256 * 1024);

        let address = reader.find_u64("address_start").ok().unwrap();
        let size = reader.find_u32("size").ok().unwrap();

        if self.conn.get_memory(&mut data, address, size as u64).is_err() {
            println!("Unable to fetch memory from {:x} - size {}", address, size);
            return;
        }

        writer.event_begin(EventType::SetMemory as u16);
        writer.write_u64("address", address);
        writer.write_data("data", &data);
        writer.event_end();
    }

    fn write_exception_location(&mut self, writer: &mut Writer) {
        writer.event_begin(EventType::SetExceptionLocation as u16);
        writer.write_u64("address", self.exception_location as u64);
        writer.write_u8("size", 4);
        writer.event_end();
    }
}

impl Backend for AmigaUaeBackend {
    fn new(service: &Service) -> Self {
        AmigaUaeBackend {
            capstone: service.get_capstone(),
            conn: GdbRemote::new(),
            exception_location: 0,
        }
    }

    fn update(&mut self, action: i32, reader: &mut Reader, writer: &mut Writer) {
        for event in reader.get_event() {
            match event {
                EVENT_MENU_EVENT => {
                    if self.conn.connect("127.0.0.1:6860").is_ok() {
                        if self.conn.request_no_ack_mode().is_ok() {
                            println!("Connected. Ready to go!");
                        } else {
                            println!("no ack request failed");
                        }
                    } else {
                        println!("Unable to connect to UAE");
                    }
                }
                EVENT_GET_DISASSEMBLY => {
                    self.write_disassembly(reader, writer);
                }

                EVENT_GET_MEMORY => {
                    self.get_memory(reader, writer);
                }

                _ => (),
            }
        }

        match action {
            ACTION_BREAK => {
                println!("Break");
            }

            ACTION_STEP => {
                let mut step_res = [0; 16];
                let mut register_data = [0; 1024];
                self.conn.step(&mut step_res).unwrap();

                    println!("steping ok!");
                    if self.conn.get_registers(&mut register_data).is_ok() {
                        println!("setting registers!");
                        self.write_registers(writer, &register_data);
                    }

                self.write_exception_location(writer);
            }
            _ => (),
        }
    }

    fn register_menu(&mut self, menu_funcs: &mut MenuFuncs) -> *mut c_void {
        let menu = menu_funcs.create_menu("Amiga UAE Debugger");
        menu_funcs.add_menu_item(menu, "Connect to UAE...", 0, 0, 0);
        menu
    }
}

#[no_mangle]
pub fn init_plugin(plugin_handler: &mut PluginHandler) {
    define_backend_plugin!(PLUGIN, b"Amiga UAE Debugger\0", AmigaUaeBackend);
    plugin_handler.register_backend(&PLUGIN);
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate diff;
extern crate bindgen;
extern crate shlex;

use bindgen::{Builder, builder, clang_version};
use std::fs;
use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::process;
use std::sync::{Once, ONCE_INIT};

#[path = "../src/options.rs"]
mod options;
use options::builder_from_flags;

// Run `rustfmt` on the given source string and return a tuple of the formatted
// bindings, and rustfmt's stderr.
fn rustfmt(source: String) -> (String, String) {
    static INSTALL_RUSTFMT: Once = ONCE_INIT;

    INSTALL_RUSTFMT.call_once(|| {
        let have_working_rustfmt = process::Command::new("rustup")
            .args(&["run", "nightly", "rustfmt", "--version"])
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null())
            .status()
            .expect("should run `rustup run nightly rustfmt --version` OK")
            .success();

        if have_working_rustfmt {
            return;
        }

        // Because `rustfmt` needs to match its exact nightly version, we update
        // both at the same time.

        let status = process::Command::new("rustup")
            .args(&["update", "nightly"])
            .status()
            .expect("should run `rustup update nightly` OK");
        assert!(status.success(), "should run `rustup update nightly` OK");

        let status = process::Command::new("rustup")
            .args(&["run", "nightly", "cargo", "install", "-f", "rustfmt-nightly"])
            .status()
            .expect("should run `rustup run nightly cargo install rustfmt-nightly` OK");
        assert!(status.success(), "should install rustfmt OK");
    });

    let mut child = process::Command::new("rustup")
        .args(&[
            "run",
            "nightly",
            "rustfmt",
            "--config-path",
            concat!(env!("CARGO_MANIFEST_DIR"), "/tests/rustfmt.toml")
        ])
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .spawn()
        .expect("should spawn `rustup run nightly rustfmt`");

    let mut stdin = child.stdin.take().unwrap();
    let mut stdout = child.stdout.take().unwrap();
    let mut stderr = child.stderr.take().unwrap();

    // Write to stdin in a new thread, so that we can read from stdout on this
    // thread. This keeps the child from blocking on writing to its stdout which
    // might block us from writing to its stdin.
    let stdin_handle = ::std::thread::spawn(move || {
        stdin.write_all(source.as_bytes())
    });

    // Read stderr on a new thread for similar reasons.
    let stderr_handle = ::std::thread::spawn(move || {
        let mut output = vec![];
        io::copy(&mut stderr, &mut output)
            .map(|_| String::from_utf8_lossy(&output).to_string())
    });

    let mut output = vec![];
    io::copy(&mut stdout, &mut output)
        .expect("Should copy stdout into vec OK");

    // Ignore actual rustfmt status because it is often non-zero for trivial
    // things.
    let _ = child.wait().expect("should wait on rustfmt child OK");

    stdin_handle.join()
        .expect("writer thread should not have panicked")
        .expect("should have written to child rustfmt's stdin OK");

    let bindings = String::from_utf8(output)
        .expect("rustfmt should only emit valid utf-8");

    let stderr = stderr_handle.join()
        .expect("stderr reader thread should not have panicked")
        .expect("should have read child rustfmt's stderr OK");

    (bindings, stderr)
}

fn compare_generated_header(
    header: &PathBuf,
    builder: Builder,
) -> Result<(), Error> {
    let file_name = try!(header.file_name().ok_or(Error::new(
        ErrorKind::Other,
        "compare_generated_header expects a file",
    )));

    let mut expectation = PathBuf::from(header);
    expectation.pop();
    expectation.pop();
    expectation.push("expectations");
    expectation.push("tests");
    expectation.push(file_name);
    expectation.set_extension("rs");

    // If the expectation file doesn't exist, see if we have different test
    // expectations for different libclang versions.
    if !expectation.is_file() {
        let file_name = expectation.file_name().unwrap().to_owned();
        expectation.pop();

        if cfg!(feature = "testing_only_libclang_4") {
            expectation.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expectation.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expectation.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {}
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expectation.push(format!("libclang-{}", version_str));
                }
            }
        }

        expectation.push(file_name);

        if !expectation.is_file() {
            panic!(
                "missing test expectation file and/or 'testing_only_libclang_$VERSION' \
                    feature for header '{}'; looking for expectation file at '{}'",
                header.display(),
                expectation.display()
            );
        }
    }

    // We skip the generate() error here so we get a full diff below
    let (actual, rustfmt_stderr) = match builder.generate() {
        Ok(bindings) => {
            let actual = bindings.to_string();
            rustfmt(actual)
        }
        Err(()) => ("<error generating bindings>".to_string(), "".to_string()),
    };
    println!("{}", rustfmt_stderr);

    let mut expected = String::new();
    {
        if let Ok(expectation_file) = fs::File::open(&expectation) {
            try!(BufReader::new(expectation_file).read_to_string(&mut expected));
        }
    }

    let (expected, rustfmt_stderr) = rustfmt(expected);
    println!("{}", rustfmt_stderr);

    if actual == expected {
        if !actual.is_empty() {
            return Ok(());
        }
        return Err(Error::new(
            ErrorKind::Other,
            "Something's gone really wrong!",
        ));
    }

    println!("{}", rustfmt_stderr);

    println!("diff expected generated");
    println!("--- expected: {:?}", expectation);
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&expected, &actual) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Override the diff.
    {
        let mut expectation_file = try!(fs::File::create(&expectation));
        try!(expectation_file.write_all(actual.as_bytes()));
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    let source = try!(fs::File::open(header));
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = try!(line);
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line.split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags
                .into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        } else if line.contains("bindgen-generate-bindings-on-linux-only") &&
                   !cfg!(target_os = "linux")
        {
            return Ok(None);
        }
    }

    // Windows platform has various different conventions than *nix platforms,
    // e.g. default enum underlying type, struct padding, mangling. Most tests
    // were written and checked on Linux and macOS, and thus they could fail on
    // Windows. We just make those tests targetting Linux instead as far as one
    // isn't annotated for a specific target.
    if cfg!(target_os = "windows") {
        if flags.iter().all(|flag| !flag.starts_with("--target=")) {
            if !flags.iter().any(|flag| flag == "--") {
                flags.push("--".into());
            }
            flags.push("--target=x86_64-unknown-linux".into());
        }
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = try!(header.to_str().ok_or(Error::new(
        ErrorKind::Other,
        "Invalid header file name",
    )));

    let prepend = [
        "bindgen",
        "--with-derive-default",
        header_str,
        "--raw-line",
        "",
        "--raw-line",
        "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
        "--raw-line",
        "",
    ];

    let args = prepend.into_iter().map(ToString::to_string).chain(
        flags
            .into_iter(),
    );

    builder_from_flags(args).map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => (
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header)
                .and_then(|builder| {
                    if let Some(builder) = builder {
                        compare_generated_header(&header, builder)
                    } else {
                        Ok(())
                    }
                });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    )
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_header_contents() {
    let actual = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let (expected, _) = rustfmt("/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
".to_string());

    assert_eq!(
        expected,
        actual
    );
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/tests/headers/func_ptr.h"
        ))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h"))
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let expected = include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"
    ));
    let (expected, _) = rustfmt(expected.to_string());

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}

#[test]
// Doesn't support executing sh file on Windows.
// We may want to implement it in Rust so that we support all systems.
#[cfg(not(target_os = "windows"))]
fn no_system_header_includes() {
    use std::process::Command;
    assert!(
        Command::new("./ci/no-includes.sh")
            .current_dir(env!("CARGO_MANIFEST_DIR"))
            .spawn()
            .expect("should spawn ./ci/no-includes.sh OK")
            .wait()
            .expect("should wait for ./ci/no-includes OK")
            .success()
    );
}

#[test]
fn dump_preprocessed_input() {
    let arg_keyword =
        concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");
    let empty_layout = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/headers/cpp-empty-layout.hpp"
    );

    builder()
        .header(arg_keyword)
        .header(empty_layout)
        .dump_preprocessed_input()
        .expect("should dump preprocessed input");

    fn slurp(p: &str) -> String {
        let mut contents = String::new();
        let mut file = fs::File::open(p).unwrap();
        file.read_to_string(&mut contents).unwrap();
        contents
    }

    let bindgen_ii = slurp("__bindgen.ii");
    let arg_keyword = slurp(arg_keyword);
    let empty_layout = slurp(empty_layout);

    assert!(
        bindgen_ii.find(&arg_keyword).is_some(),
        "arg_keyword.hpp is in the preprocessed file"
    );
    assert!(
        bindgen_ii.find(&empty_layout).is_some(),
        "cpp-empty-layout.hpp is in the preprocessed file"
    );
}
<commit_msg>Just check for `rustfmt`; don't install it<commit_after>extern crate clap;
extern crate diff;
extern crate bindgen;
extern crate shlex;

use bindgen::{Builder, builder, clang_version};
use std::fs;
use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;
use std::process;
use std::sync::{Once, ONCE_INIT};

#[path = "../src/options.rs"]
mod options;
use options::builder_from_flags;

// Run `rustfmt` on the given source string and return a tuple of the formatted
// bindings, and rustfmt's stderr.
fn rustfmt(source: String) -> (String, String) {
    static CHECK_RUSTFMT: Once = ONCE_INIT;

    CHECK_RUSTFMT.call_once(|| {
        let have_working_rustfmt = process::Command::new("rustup")
            .args(&["run", "nightly", "rustfmt", "--version"])
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null())
            .status()
            .ok()
            .map_or(false, |status| status.success());

        if !have_working_rustfmt {
            panic!("
The latest `rustfmt` is required to run the `bindgen` test suite. Install
`rustfmt` with:

    $ rustup update nightly
    $ rustup run nightly cargo install -f rustfmt-nightly
");
        }
    });

    let mut child = process::Command::new("rustup")
        .args(&[
            "run",
            "nightly",
            "rustfmt",
            "--config-path",
            concat!(env!("CARGO_MANIFEST_DIR"), "/tests/rustfmt.toml")
        ])
        .stdin(process::Stdio::piped())
        .stdout(process::Stdio::piped())
        .stderr(process::Stdio::piped())
        .spawn()
        .expect("should spawn `rustup run nightly rustfmt`");

    let mut stdin = child.stdin.take().unwrap();
    let mut stdout = child.stdout.take().unwrap();
    let mut stderr = child.stderr.take().unwrap();

    // Write to stdin in a new thread, so that we can read from stdout on this
    // thread. This keeps the child from blocking on writing to its stdout which
    // might block us from writing to its stdin.
    let stdin_handle = ::std::thread::spawn(move || {
        stdin.write_all(source.as_bytes())
    });

    // Read stderr on a new thread for similar reasons.
    let stderr_handle = ::std::thread::spawn(move || {
        let mut output = vec![];
        io::copy(&mut stderr, &mut output)
            .map(|_| String::from_utf8_lossy(&output).to_string())
    });

    let mut output = vec![];
    io::copy(&mut stdout, &mut output)
        .expect("Should copy stdout into vec OK");

    // Ignore actual rustfmt status because it is often non-zero for trivial
    // things.
    let _ = child.wait().expect("should wait on rustfmt child OK");

    stdin_handle.join()
        .expect("writer thread should not have panicked")
        .expect("should have written to child rustfmt's stdin OK");

    let bindings = String::from_utf8(output)
        .expect("rustfmt should only emit valid utf-8");

    let stderr = stderr_handle.join()
        .expect("stderr reader thread should not have panicked")
        .expect("should have read child rustfmt's stderr OK");

    (bindings, stderr)
}

fn compare_generated_header(
    header: &PathBuf,
    builder: Builder,
) -> Result<(), Error> {
    let file_name = try!(header.file_name().ok_or(Error::new(
        ErrorKind::Other,
        "compare_generated_header expects a file",
    )));

    let mut expectation = PathBuf::from(header);
    expectation.pop();
    expectation.pop();
    expectation.push("expectations");
    expectation.push("tests");
    expectation.push(file_name);
    expectation.set_extension("rs");

    // If the expectation file doesn't exist, see if we have different test
    // expectations for different libclang versions.
    if !expectation.is_file() {
        let file_name = expectation.file_name().unwrap().to_owned();
        expectation.pop();

        if cfg!(feature = "testing_only_libclang_4") {
            expectation.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expectation.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expectation.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {}
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expectation.push(format!("libclang-{}", version_str));
                }
            }
        }

        expectation.push(file_name);

        if !expectation.is_file() {
            panic!(
                "missing test expectation file and/or 'testing_only_libclang_$VERSION' \
                    feature for header '{}'; looking for expectation file at '{}'",
                header.display(),
                expectation.display()
            );
        }
    }

    // We skip the generate() error here so we get a full diff below
    let (actual, rustfmt_stderr) = match builder.generate() {
        Ok(bindings) => {
            let actual = bindings.to_string();
            rustfmt(actual)
        }
        Err(()) => ("<error generating bindings>".to_string(), "".to_string()),
    };
    println!("{}", rustfmt_stderr);

    let mut expected = String::new();
    {
        if let Ok(expectation_file) = fs::File::open(&expectation) {
            try!(BufReader::new(expectation_file).read_to_string(&mut expected));
        }
    }

    let (expected, rustfmt_stderr) = rustfmt(expected);
    println!("{}", rustfmt_stderr);

    if actual == expected {
        if !actual.is_empty() {
            return Ok(());
        }
        return Err(Error::new(
            ErrorKind::Other,
            "Something's gone really wrong!",
        ));
    }

    println!("{}", rustfmt_stderr);

    println!("diff expected generated");
    println!("--- expected: {:?}", expectation);
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&expected, &actual) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Override the diff.
    {
        let mut expectation_file = try!(fs::File::create(&expectation));
        try!(expectation_file.write_all(actual.as_bytes()));
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    let source = try!(fs::File::open(header));
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = try!(line);
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line.split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags
                .into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        } else if line.contains("bindgen-generate-bindings-on-linux-only") &&
                   !cfg!(target_os = "linux")
        {
            return Ok(None);
        }
    }

    // Windows platform has various different conventions than *nix platforms,
    // e.g. default enum underlying type, struct padding, mangling. Most tests
    // were written and checked on Linux and macOS, and thus they could fail on
    // Windows. We just make those tests targetting Linux instead as far as one
    // isn't annotated for a specific target.
    if cfg!(target_os = "windows") {
        if flags.iter().all(|flag| !flag.starts_with("--target=")) {
            if !flags.iter().any(|flag| flag == "--") {
                flags.push("--".into());
            }
            flags.push("--target=x86_64-unknown-linux".into());
        }
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = try!(header.to_str().ok_or(Error::new(
        ErrorKind::Other,
        "Invalid header file name",
    )));

    let prepend = [
        "bindgen",
        "--with-derive-default",
        header_str,
        "--raw-line",
        "",
        "--raw-line",
        "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
        "--raw-line",
        "",
    ];

    let args = prepend.into_iter().map(ToString::to_string).chain(
        flags
            .into_iter(),
    );

    builder_from_flags(args).map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => (
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header)
                .and_then(|builder| {
                    if let Some(builder) = builder {
                        compare_generated_header(&header, builder)
                    } else {
                        Ok(())
                    }
                });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    )
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_header_contents() {
    let actual = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let (expected, _) = rustfmt("/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
".to_string());

    assert_eq!(
        expected,
        actual
    );
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/tests/headers/func_ptr.h"
        ))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/char.h"))
        .generate()
        .unwrap()
        .to_string();

    let (actual, stderr) = rustfmt(actual);
    println!("{}", stderr);

    let expected = include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"
    ));
    let (expected, _) = rustfmt(expected.to_string());

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}

#[test]
// Doesn't support executing sh file on Windows.
// We may want to implement it in Rust so that we support all systems.
#[cfg(not(target_os = "windows"))]
fn no_system_header_includes() {
    use std::process::Command;
    assert!(
        Command::new("./ci/no-includes.sh")
            .current_dir(env!("CARGO_MANIFEST_DIR"))
            .spawn()
            .expect("should spawn ./ci/no-includes.sh OK")
            .wait()
            .expect("should wait for ./ci/no-includes OK")
            .success()
    );
}

#[test]
fn dump_preprocessed_input() {
    let arg_keyword =
        concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/arg_keyword.hpp");
    let empty_layout = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/tests/headers/cpp-empty-layout.hpp"
    );

    builder()
        .header(arg_keyword)
        .header(empty_layout)
        .dump_preprocessed_input()
        .expect("should dump preprocessed input");

    fn slurp(p: &str) -> String {
        let mut contents = String::new();
        let mut file = fs::File::open(p).unwrap();
        file.read_to_string(&mut contents).unwrap();
        contents
    }

    let bindgen_ii = slurp("__bindgen.ii");
    let arg_keyword = slurp(arg_keyword);
    let empty_layout = slurp(empty_layout);

    assert!(
        bindgen_ii.find(&arg_keyword).is_some(),
        "arg_keyword.hpp is in the preprocessed file"
    );
    assert!(
        bindgen_ii.find(&empty_layout).is_some(),
        "cpp-empty-layout.hpp is in the preprocessed file"
    );
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate diff;
extern crate bindgen;
extern crate shlex;

use bindgen::{Builder, builder};
use std::fs;
use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;

#[path="../src/options.rs"]
mod options;
use options::builder_from_flags;

fn compare_generated_header(header: &PathBuf,
                            builder: Builder)
                            -> Result<(), Error> {
    let file_name = try!(header.file_name()
        .ok_or(Error::new(ErrorKind::Other, "spawn_bindgen expects a file")));

    let mut expected = PathBuf::from(header);
    expected.pop();
    expected.pop();
    expected.push("expectations");
    expected.push("tests");
    expected.push(file_name);
    expected.set_extension("rs");

    // If the expectation file doesn't exist, see if we have different test
    // expectations for different libclang versions.
    if !expected.is_file() {
        let file_name = expected.file_name().unwrap().to_owned();
        expected.pop();

        if cfg!(feature = "testing_only_libclang_4") {
            expected.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expected.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expected.push("libclang-3.8");
        }

        expected.push(file_name);

        if !expected.is_file() {
            panic!("missing test expectation file and/or 'testing_only_libclang_$VERSION' \
                    feature for header '{}'; looking for expectation file at '{}'",
                   header.display(),
                   expected.display());
        }
    }

    // We skip the generate() error here so we get a full diff below
    let output = match builder.generate() {
        Ok(bindings) => bindings.to_string(),
        Err(_) => "".to_string(),
    };

    let mut buffer = String::new();
    {
        if let Ok(expected_file) = fs::File::open(&expected) {
            try!(BufReader::new(expected_file).read_to_string(&mut buffer));
        }
    }

    if output == buffer {
        if !output.is_empty() {
            return Ok(());
        }
        return Err(Error::new(ErrorKind::Other,
                              "Something's gone really wrong!"));
    }

    println!("diff expected generated");
    println!("--- expected: {:?}", expected);
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&buffer, &output) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Override the diff.
    {
        let mut expected_file = try!(fs::File::create(&expected));
        try!(expected_file.write_all(output.as_bytes()));
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    let source = try!(fs::File::open(header));
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = try!(line);
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line.split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags.into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        } else if line.contains("bindgen-generate-bindings-on-linux-only") &&
          !cfg!(target_os = "linux") {
              return Ok(None);
        }
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = try!(header.to_str()
        .ok_or(Error::new(ErrorKind::Other, "Invalid header file name")));

    let prepend = ["bindgen",
                   "--with-derive-default",
                   header_str,
                   "--raw-line",
                   "",
                   "--raw-line",
                   "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
                   "--raw-line",
                   ""];

    let args = prepend.into_iter()
        .map(ToString::to_string)
        .chain(flags.into_iter());

    builder_from_flags(args)
        .map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => (
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header)
                .and_then(|builder| {
                    if let Some(builder) = builder {
                        compare_generated_header(&header, builder)
                    } else {
                        Ok(())
                    }
                });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    )
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_header_contents() {
    let bindings = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .generate()
        .unwrap()
        .to_string();
    assert_eq!(bindings, "/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
");
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/func_ptr.h"))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/enum.h"))
        .generate()
        .unwrap()
        .to_string();

    let expected = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"));

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}
<commit_msg>Automatically detect libclang version when testing<commit_after>extern crate clap;
extern crate diff;
extern crate bindgen;
extern crate shlex;

use bindgen::{Builder, builder, clang_version};
use std::fs;
use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Write};
use std::path::PathBuf;

#[path="../src/options.rs"]
mod options;
use options::builder_from_flags;

fn compare_generated_header(header: &PathBuf,
                            builder: Builder)
                            -> Result<(), Error> {
    let file_name = try!(header.file_name()
        .ok_or(Error::new(ErrorKind::Other, "spawn_bindgen expects a file")));

    let mut expected = PathBuf::from(header);
    expected.pop();
    expected.pop();
    expected.push("expectations");
    expected.push("tests");
    expected.push(file_name);
    expected.set_extension("rs");

    // If the expectation file doesn't exist, see if we have different test
    // expectations for different libclang versions.
    if !expected.is_file() {
        let file_name = expected.file_name().unwrap().to_owned();
        expected.pop();

        if cfg!(feature = "testing_only_libclang_4") {
            expected.push("libclang-4");
        } else if cfg!(feature = "testing_only_libclang_3_9") {
            expected.push("libclang-3.9");
        } else if cfg!(feature = "testing_only_libclang_3_8") {
            expected.push("libclang-3.8");
        } else {
            match clang_version().parsed {
                None => {},
                Some(version) => {
                    let (maj, min) = version;
                    let version_str = if maj >= 4 {
                        "4".to_owned()
                    } else {
                        format!("{}.{}", maj, min)
                    };
                    expected.push(format!("libclang-{}", version_str));
                }
            }
        }

        expected.push(file_name);

        if !expected.is_file() {
            panic!("missing test expectation file and/or 'testing_only_libclang_$VERSION' \
                    feature for header '{}'; looking for expectation file at '{}'",
                   header.display(),
                   expected.display());
        }
    }

    // We skip the generate() error here so we get a full diff below
    let output = match builder.generate() {
        Ok(bindings) => bindings.to_string(),
        Err(_) => "".to_string(),
    };

    let mut buffer = String::new();
    {
        if let Ok(expected_file) = fs::File::open(&expected) {
            try!(BufReader::new(expected_file).read_to_string(&mut buffer));
        }
    }

    if output == buffer {
        if !output.is_empty() {
            return Ok(());
        }
        return Err(Error::new(ErrorKind::Other,
                              "Something's gone really wrong!"));
    }

    println!("diff expected generated");
    println!("--- expected: {:?}", expected);
    println!("+++ generated from: {:?}", header);

    for diff in diff::lines(&buffer, &output) {
        match diff {
            diff::Result::Left(l) => println!("-{}", l),
            diff::Result::Both(l, _) => println!(" {}", l),
            diff::Result::Right(r) => println!("+{}", r),
        }
    }

    // Override the diff.
    {
        let mut expected_file = try!(fs::File::create(&expected));
        try!(expected_file.write_all(output.as_bytes()));
    }

    Err(Error::new(ErrorKind::Other, "Header and binding differ!"))
}

fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
    let source = try!(fs::File::open(header));
    let reader = BufReader::new(source);

    // Scoop up bindgen-flags from test header
    let mut flags = Vec::with_capacity(2);

    for line in reader.lines() {
        let line = try!(line);
        if !line.starts_with("// bindgen") {
            continue;
        }

        if line.contains("bindgen-flags: ") {
            let extra_flags = line.split("bindgen-flags: ")
                .last()
                .and_then(shlex::split)
                .unwrap();
            flags.extend(extra_flags.into_iter());
        } else if line.contains("bindgen-osx-only") {
            let prepend_flags = ["--raw-line", "#![cfg(target_os=\"macos\")]"];
            flags = prepend_flags.into_iter()
                .map(ToString::to_string)
                .chain(flags)
                .collect();
        } else if line.contains("bindgen-generate-bindings-on-linux-only") &&
          !cfg!(target_os = "linux") {
              return Ok(None);
        }
    }

    // Fool builder_from_flags() into believing it has real env::args_os...
    // - add "bindgen" as executable name 0th element
    // - add header filename as 1st element
    // - prepend raw lines so they're in the right order for expected output
    // - append the test header's bindgen flags
    let header_str = try!(header.to_str()
        .ok_or(Error::new(ErrorKind::Other, "Invalid header file name")));

    let prepend = ["bindgen",
                   "--with-derive-default",
                   header_str,
                   "--raw-line",
                   "",
                   "--raw-line",
                   "#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]",
                   "--raw-line",
                   ""];

    let args = prepend.into_iter()
        .map(ToString::to_string)
        .chain(flags.into_iter());

    builder_from_flags(args)
        .map(|(builder, _, _)| Some(builder))
}

macro_rules! test_header {
    ($function:ident, $header:expr) => (
        #[test]
        fn $function() {
            let header = PathBuf::from($header);
            let result = create_bindgen_builder(&header)
                .and_then(|builder| {
                    if let Some(builder) = builder {
                        compare_generated_header(&header, builder)
                    } else {
                        Ok(())
                    }
                });

            if let Err(err) = result {
                panic!("{}", err);
            }
        }
    )
}

// This file is generated by build.rs
include!(concat!(env!("OUT_DIR"), "/tests.rs"));

#[test]
fn test_header_contents() {
    let bindings = builder()
        .header_contents("test.h", "int foo(const char* a);")
        .generate()
        .unwrap()
        .to_string();
    assert_eq!(bindings, "/* automatically generated by rust-bindgen */

extern \"C\" {
    pub fn foo(a: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
}
");
}

#[test]
fn test_multiple_header_calls_in_builder() {
    let actual = builder()
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/func_ptr.h"))
        .header(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/headers/enum.h"))
        .generate()
        .unwrap()
        .to_string();

    let expected = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/expectations/tests/test_multiple_header_calls_in_builder.rs"));

    if actual != expected {
        println!("Generated bindings differ from expected!");

        for diff in diff::lines(&actual, &expected) {
            match diff {
                diff::Result::Left(l) => println!("-{}", l),
                diff::Result::Both(l, _) => println!(" {}", l),
                diff::Result::Right(r) => println!("+{}", r),
            }
        }

        panic!();
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]

#[plugin]
extern crate glium_macros;
extern crate glutin;
extern crate glium;
#[cfg(feature = "cgmath")]
extern crate cgmath;
#[cfg(feature = "image")]
extern crate image;

use glium::Surface;
use glium::DisplayBuild;
#[cfg(feature = "cgmath")]
use cgmath::FixedArray;
use std::old_io::BufReader;

#[cfg(not(all(feature = "cgmath", feature = "image")))]
fn main() {
    println!("This example requires the `cgmath` and `image` features to be enabled");
}

#[cfg(all(feature = "cgmath", feature = "image"))]
fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
        .with_dimensions(800, 500)
        .with_title(format!("Glium Deferred Example"))
        .build_glium()
        .unwrap();

    let image = image::load(BufReader::new(include_bytes!("../tests/fixture/opengl.png")), image::PNG).unwrap();
    let opengl_texture = glium::texture::Texture2d::new(&display, image);

    let floor_vertex_buffer = {
        #[vertex_format]
        #[derive(Copy)]
        struct Vertex {
            position: [f32; 4],
            normal: [f32; 4],
            texcoord: [f32; 2]
        }

        glium::VertexBuffer::new(&display,
            vec![
                Vertex { position: [-1.0, 0.0, -1.0, 1.0], normal: [0.0, 1.0, 0.0, 1.0], texcoord: [0.0, 0.0] },
                Vertex { position: [1.0, 0.0, -1.0, 1.0], normal: [0.0, 1.0, 0.0, 1.0], texcoord: [1.0, 0.0] },
                Vertex { position: [1.0, 0.0, 1.0, 1.0], normal: [0.0, 1.0, 0.0, 1.0], texcoord: [1.0, 1.0] },
                Vertex { position: [-1.0, 0.0, 1.0, 1.0], normal: [0.0, 1.0, 0.0, 1.0], texcoord: [0.0, 1.0] },
            ]
        )
    };

    let floor_index_buffer = glium::IndexBuffer::new(&display,
        glium::index::TrianglesList(vec![0u16, 1, 2, 0, 2, 3]));

    let quad_vertex_buffer = {
        #[vertex_format]
        #[derive(Copy)]
        struct Vertex {
            position: [f32; 4],
            texcoord: [f32; 2]
        }

        glium::VertexBuffer::new(&display,
            vec![
                Vertex { position: [0.0, 0.0, 0.0, 1.0], texcoord: [0.0, 0.0] },
                Vertex { position: [800.0, 0.0, 0.0, 1.0], texcoord: [1.0, 0.0] },
                Vertex { position: [800.0, 500.0, 0.0, 1.0], texcoord: [1.0, 1.0] },
                Vertex { position: [0.0, 500.0, 0.0, 1.0], texcoord: [0.0, 1.0] },
            ]
        )
    };

    let quad_index_buffer = glium::IndexBuffer::new(&display,
        glium::index::TrianglesList(vec![0u16, 1, 2, 0, 2, 3]));

    // compiling shaders and linking them together
    let prepass_program = glium::Program::from_source(&display,
        // vertex shader
        "
            #version 130

            uniform mat4 perspective_matrix;
            uniform mat4 view_matrix;
            uniform mat4 model_matrix;

            in vec4 position;
            in vec4 normal;
            in vec2 texcoord;

            smooth out vec4 frag_position;
            smooth out vec4 frag_normal;
            smooth out vec2 frag_texcoord;

            void main() {
                frag_position = model_matrix * position;
                frag_normal = model_matrix * normal;
                frag_texcoord = texcoord;
                gl_Position = perspective_matrix * view_matrix * frag_position;
            }
        ",

        // fragment shader
        "
            #version 130

            uniform sampler2D texture;

            smooth in vec4 frag_position;
            smooth in vec4 frag_normal;
            smooth in vec2 frag_texcoord;

            out vec4 output1;
            out vec4 output2;
            out vec4 output3;
            out vec4 output4;

            void main() {
                output1 = vec4(frag_position);
                output2 = vec4(frag_normal);
                output3 = texture2D(texture, frag_texcoord);
                output4 = vec4(1.0, 0.0, 1.0, 1.0);
            }
        ",

        // geometry shader
        None)
        .unwrap();

    let lighting_program = glium::Program::from_source(&display,
        // vertex shader
        "
            #version 130

            uniform mat4 matrix;

            in vec4 position;
            in vec2 texcoord;

            smooth out vec2 frag_texcoord;

            void main() {
                gl_Position = matrix * position;
                frag_texcoord = texcoord;
            }
        ",

        // fragment shader
        "
            #version 130

            uniform sampler2D position_texture;
            uniform sampler2D normal_texture;
            uniform vec4 light_position;
            uniform vec3 light_color;
            uniform vec3 light_attenuation;
            uniform float light_radius;

            smooth in vec2 frag_texcoord;

            out vec4 frag_output;

            void main() {
                vec4 position = texture2D(position_texture, frag_texcoord);
                vec4 normal = texture2D(normal_texture, frag_texcoord);
                vec3 light_vector = light_position.xyz - position.xyz;
                float light_distance = abs(length(light_vector));
                vec3 normal_vector = normalize(normal.xyz);
                float diffuse = max(dot(normal_vector, light_vector), 0.0);
                if (diffuse > 0.0) {
                    float attenuation_factor = 1.0 / (
                        light_attenuation.x +
                        (light_attenuation.y * light_distance) +
                        (light_attenuation.z * light_distance * light_distance)
                    );
                    attenuation_factor *= (1.0 - pow((light_distance / light_radius), 2.0));
                    diffuse *= attenuation_factor;

                }
                frag_output = vec4(light_color * diffuse, 1.0);
            }
        ",

        // geometry shader
        None)
        .unwrap();

    // compiling shaders and linking them together
    let composition_program = glium::Program::from_source(&display,
        // vertex shader
        "
            #version 130

            uniform mat4 matrix;

            in vec4 position;
            in vec2 texcoord;

            smooth out vec2 frag_texcoord;

            void main() {
                frag_texcoord = texcoord;
                gl_Position = matrix * position;
            }
        ",

        // fragment shader
        "
            #version 130

            uniform sampler2D decal_texture;
            uniform sampler2D lighting_texture;

            smooth in vec2 frag_texcoord;

            out vec4 frag_output;

            void main() {
                vec4 lighting_value = texture2D(lighting_texture, frag_texcoord);
                frag_output = vec4(texture2D(decal_texture, frag_texcoord).rgb * lighting_value.rgb, 1.0);
            }
        ",

        // geometry shader
        None)
        .unwrap();

    // creating the uniforms structure
    #[uniforms]
    #[derive(Copy)]
    struct PrepassUniforms<'a> {
        perspective_matrix: [[f32; 4]; 4],
        view_matrix: [[f32; 4]; 4],
        model_matrix: [[f32; 4]; 4],
        texture: &'a glium::texture::Texture2d
    }

    #[uniforms]
    #[derive(Copy)]
    struct LightingUniforms<'a> {
        matrix: [[f32; 4]; 4],
        position_texture: &'a glium::texture::Texture2d,
        normal_texture: &'a glium::texture::Texture2d,
        light_position: [f32; 4],
        light_color: [f32; 3],
        light_attenuation: [f32; 3],
        light_radius: f32
    }

    #[uniforms]
    #[derive(Copy)]
    struct CompositionUniforms<'a> {
        matrix: [[f32; 4]; 4],
        decal_texture: &'a glium::texture::Texture2d,
        lighting_texture: &'a glium::texture::Texture2d
    }

    struct Light<'a> {
        position: [f32; 4],
        color: [f32; 3],
        attenuation: [f32; 3],
        radius: f32
    }

    let texture1 = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let texture2 = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let texture3 = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let texture4 = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let depthtexture = glium::texture::DepthTexture2d::new_empty(&display, glium::texture::DepthFormat::F32, 800, 500);
    let output = &[("output1", &texture1), ("output2", &texture2), ("output3", &texture3), ("output4", &texture4)];
    let mut framebuffer = glium::framebuffer::MultiOutputFrameBuffer::with_depth_buffer(&display, output, &depthtexture);

    let light_texture = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let mut light_buffer = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, &light_texture, &depthtexture);

    let ortho_matrix: cgmath::Matrix4<f32> = cgmath::ortho(0.0, 800.0, 0.0, 500.0, -1.0, 1.0);
    let fixed_ortho_matrix = ortho_matrix.as_fixed();

    let perspective_matrix: cgmath::Matrix4<f32> = cgmath::perspective(cgmath::deg(45.0), 1.333, 0.0001, 100.0);
    let fixed_perspective_matrix = perspective_matrix.as_fixed();
    let view_eye: cgmath::Point3<f32> = cgmath::Point3::new(0.0, 2.0, -2.0);
    let view_center: cgmath::Point3<f32> = cgmath::Point3::new(0.0, 0.0, 0.0);
    let view_up: cgmath::Vector3<f32> = cgmath::Vector3::new(0.0, 1.0, 0.0);
    let view_matrix: cgmath::Matrix4<f32> = cgmath::Matrix4::look_at(&view_eye, &view_center, &view_up);
    let fixed_view_matrix = view_matrix.as_fixed();
    let model_matrix: cgmath::Matrix4<f32> = cgmath::Matrix4::identity();
    let fixed_model_matrix = model_matrix.as_fixed();

    let lights = [
        Light {
            position: [1.0, 1.0, 1.0, 1.0],
            attenuation: [0.8, 0.00125, 0.0000001],
            color: [1.0, 0.0, 0.0],
            radius: 1.5
        },
        Light {
            position: [0.0, 1.0, 0.0, 1.0],
            attenuation: [0.8, 0.00125, 0.0000001],
            color: [0.0, 1.0, 0.0],
            radius: 1.5
        },
        Light {
            position: [0.0, 1.0, 1.0, 1.0],
            attenuation: [0.8, 0.00125, 0.0000001],
            color: [0.0, 0.0, 1.0],
            radius: 1.5
        },
        Light {
            position: [1.0, 1.0, 0.0, 1.0],
            attenuation: [0.8, 0.00125, 0.0000001],
            color: [1.0, 1.0, 0.0],
            radius: 1.5
        }
    ];

    // the main loop
    // each cycle will draw once
    'main: loop {
        use std::old_io::timer;
        use std::time::Duration;

        // prepass
        let uniforms = PrepassUniforms {
            perspective_matrix: *fixed_perspective_matrix,
            view_matrix: *fixed_view_matrix,
            model_matrix: *fixed_model_matrix,
            texture: &opengl_texture
        };
        framebuffer.draw(&floor_vertex_buffer, &floor_index_buffer, &prepass_program, &uniforms, &std::default::Default::default()).unwrap();

        // lighting
        let draw_params = glium::DrawParameters {
            //depth_function: glium::DepthFunction::IfLessOrEqual,
            blending_function: Some(glium::BlendingFunction::Addition{
                source: glium::LinearBlendingFactor::One,
                destination: glium::LinearBlendingFactor::One
            }),
            .. std::default::Default::default()
        };
        light_buffer.clear_color(0.0, 0.0, 0.0, 0.0);
        for light in lights.iter() {
            let uniforms = LightingUniforms {
                matrix: *fixed_ortho_matrix,
                position_texture: &texture1,
                normal_texture: &texture2,
                light_position: light.position,
                light_attenuation: light.attenuation,
                light_color: light.color,
                light_radius: light.radius
            };
            light_buffer.draw(&quad_vertex_buffer, &quad_index_buffer, &lighting_program, &uniforms, &draw_params).unwrap();
        }

        // composition
        let uniforms = CompositionUniforms {
            matrix: *fixed_ortho_matrix,
            decal_texture: &texture3,
            lighting_texture: &light_texture
        };
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.draw(&quad_vertex_buffer, &quad_index_buffer, &composition_program, &uniforms, &std::default::Default::default()).unwrap();
        target.finish();

        // sleeping for some time in order not to use up too much CPU
        timer::sleep(Duration::milliseconds(17));

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => break 'main,
                _ => ()
            }
        }
    }
}
<commit_msg>Fix missing clear in the deferred example<commit_after>#![feature(plugin)]

#[plugin]
extern crate glium_macros;
extern crate glutin;
extern crate glium;
#[cfg(feature = "cgmath")]
extern crate cgmath;
#[cfg(feature = "image")]
extern crate image;

use glium::Surface;
use glium::DisplayBuild;
#[cfg(feature = "cgmath")]
use cgmath::FixedArray;
use std::old_io::BufReader;

#[cfg(not(all(feature = "cgmath", feature = "image")))]
fn main() {
    println!("This example requires the `cgmath` and `image` features to be enabled");
}

#[cfg(all(feature = "cgmath", feature = "image"))]
fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
        .with_dimensions(800, 500)
        .with_title(format!("Glium Deferred Example"))
        .build_glium()
        .unwrap();

    let image = image::load(BufReader::new(include_bytes!("../tests/fixture/opengl.png")), image::PNG).unwrap();
    let opengl_texture = glium::texture::Texture2d::new(&display, image);

    let floor_vertex_buffer = {
        #[vertex_format]
        #[derive(Copy)]
        struct Vertex {
            position: [f32; 4],
            normal: [f32; 4],
            texcoord: [f32; 2]
        }

        glium::VertexBuffer::new(&display,
            vec![
                Vertex { position: [-1.0, 0.0, -1.0, 1.0], normal: [0.0, 1.0, 0.0, 1.0], texcoord: [0.0, 0.0] },
                Vertex { position: [1.0, 0.0, -1.0, 1.0], normal: [0.0, 1.0, 0.0, 1.0], texcoord: [1.0, 0.0] },
                Vertex { position: [1.0, 0.0, 1.0, 1.0], normal: [0.0, 1.0, 0.0, 1.0], texcoord: [1.0, 1.0] },
                Vertex { position: [-1.0, 0.0, 1.0, 1.0], normal: [0.0, 1.0, 0.0, 1.0], texcoord: [0.0, 1.0] },
            ]
        )
    };

    let floor_index_buffer = glium::IndexBuffer::new(&display,
        glium::index::TrianglesList(vec![0u16, 1, 2, 0, 2, 3]));

    let quad_vertex_buffer = {
        #[vertex_format]
        #[derive(Copy)]
        struct Vertex {
            position: [f32; 4],
            texcoord: [f32; 2]
        }

        glium::VertexBuffer::new(&display,
            vec![
                Vertex { position: [0.0, 0.0, 0.0, 1.0], texcoord: [0.0, 0.0] },
                Vertex { position: [800.0, 0.0, 0.0, 1.0], texcoord: [1.0, 0.0] },
                Vertex { position: [800.0, 500.0, 0.0, 1.0], texcoord: [1.0, 1.0] },
                Vertex { position: [0.0, 500.0, 0.0, 1.0], texcoord: [0.0, 1.0] },
            ]
        )
    };

    let quad_index_buffer = glium::IndexBuffer::new(&display,
        glium::index::TrianglesList(vec![0u16, 1, 2, 0, 2, 3]));

    // compiling shaders and linking them together
    let prepass_program = glium::Program::from_source(&display,
        // vertex shader
        "
            #version 130

            uniform mat4 perspective_matrix;
            uniform mat4 view_matrix;
            uniform mat4 model_matrix;

            in vec4 position;
            in vec4 normal;
            in vec2 texcoord;

            smooth out vec4 frag_position;
            smooth out vec4 frag_normal;
            smooth out vec2 frag_texcoord;

            void main() {
                frag_position = model_matrix * position;
                frag_normal = model_matrix * normal;
                frag_texcoord = texcoord;
                gl_Position = perspective_matrix * view_matrix * frag_position;
            }
        ",

        // fragment shader
        "
            #version 130

            uniform sampler2D texture;

            smooth in vec4 frag_position;
            smooth in vec4 frag_normal;
            smooth in vec2 frag_texcoord;

            out vec4 output1;
            out vec4 output2;
            out vec4 output3;
            out vec4 output4;

            void main() {
                output1 = vec4(frag_position);
                output2 = vec4(frag_normal);
                output3 = texture2D(texture, frag_texcoord);
                output4 = vec4(1.0, 0.0, 1.0, 1.0);
            }
        ",

        // geometry shader
        None)
        .unwrap();

    let lighting_program = glium::Program::from_source(&display,
        // vertex shader
        "
            #version 130

            uniform mat4 matrix;

            in vec4 position;
            in vec2 texcoord;

            smooth out vec2 frag_texcoord;

            void main() {
                gl_Position = matrix * position;
                frag_texcoord = texcoord;
            }
        ",

        // fragment shader
        "
            #version 130

            uniform sampler2D position_texture;
            uniform sampler2D normal_texture;
            uniform vec4 light_position;
            uniform vec3 light_color;
            uniform vec3 light_attenuation;
            uniform float light_radius;

            smooth in vec2 frag_texcoord;

            out vec4 frag_output;

            void main() {
                vec4 position = texture2D(position_texture, frag_texcoord);
                vec4 normal = texture2D(normal_texture, frag_texcoord);
                vec3 light_vector = light_position.xyz - position.xyz;
                float light_distance = abs(length(light_vector));
                vec3 normal_vector = normalize(normal.xyz);
                float diffuse = max(dot(normal_vector, light_vector), 0.0);
                if (diffuse > 0.0) {
                    float attenuation_factor = 1.0 / (
                        light_attenuation.x +
                        (light_attenuation.y * light_distance) +
                        (light_attenuation.z * light_distance * light_distance)
                    );
                    attenuation_factor *= (1.0 - pow((light_distance / light_radius), 2.0));
                    diffuse *= attenuation_factor;

                }
                frag_output = vec4(light_color * diffuse, 1.0);
            }
        ",

        // geometry shader
        None)
        .unwrap();

    // compiling shaders and linking them together
    let composition_program = glium::Program::from_source(&display,
        // vertex shader
        "
            #version 130

            uniform mat4 matrix;

            in vec4 position;
            in vec2 texcoord;

            smooth out vec2 frag_texcoord;

            void main() {
                frag_texcoord = texcoord;
                gl_Position = matrix * position;
            }
        ",

        // fragment shader
        "
            #version 130

            uniform sampler2D decal_texture;
            uniform sampler2D lighting_texture;

            smooth in vec2 frag_texcoord;

            out vec4 frag_output;

            void main() {
                vec4 lighting_value = texture2D(lighting_texture, frag_texcoord);
                frag_output = vec4(texture2D(decal_texture, frag_texcoord).rgb * lighting_value.rgb, 1.0);
            }
        ",

        // geometry shader
        None)
        .unwrap();

    // creating the uniforms structure
    #[uniforms]
    #[derive(Copy)]
    struct PrepassUniforms<'a> {
        perspective_matrix: [[f32; 4]; 4],
        view_matrix: [[f32; 4]; 4],
        model_matrix: [[f32; 4]; 4],
        texture: &'a glium::texture::Texture2d
    }

    #[uniforms]
    #[derive(Copy)]
    struct LightingUniforms<'a> {
        matrix: [[f32; 4]; 4],
        position_texture: &'a glium::texture::Texture2d,
        normal_texture: &'a glium::texture::Texture2d,
        light_position: [f32; 4],
        light_color: [f32; 3],
        light_attenuation: [f32; 3],
        light_radius: f32
    }

    #[uniforms]
    #[derive(Copy)]
    struct CompositionUniforms<'a> {
        matrix: [[f32; 4]; 4],
        decal_texture: &'a glium::texture::Texture2d,
        lighting_texture: &'a glium::texture::Texture2d
    }

    struct Light<'a> {
        position: [f32; 4],
        color: [f32; 3],
        attenuation: [f32; 3],
        radius: f32
    }

    let texture1 = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let texture2 = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let texture3 = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let texture4 = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let depthtexture = glium::texture::DepthTexture2d::new_empty(&display, glium::texture::DepthFormat::F32, 800, 500);
    let output = &[("output1", &texture1), ("output2", &texture2), ("output3", &texture3), ("output4", &texture4)];
    let mut framebuffer = glium::framebuffer::MultiOutputFrameBuffer::with_depth_buffer(&display, output, &depthtexture);

    let light_texture = glium::texture::Texture2d::new_empty(&display, glium::texture::UncompressedFloatFormat::F32F32F32F32, 800, 500);
    let mut light_buffer = glium::framebuffer::SimpleFrameBuffer::with_depth_buffer(&display, &light_texture, &depthtexture);

    let ortho_matrix: cgmath::Matrix4<f32> = cgmath::ortho(0.0, 800.0, 0.0, 500.0, -1.0, 1.0);
    let fixed_ortho_matrix = ortho_matrix.as_fixed();

    let perspective_matrix: cgmath::Matrix4<f32> = cgmath::perspective(cgmath::deg(45.0), 1.333, 0.0001, 100.0);
    let fixed_perspective_matrix = perspective_matrix.as_fixed();
    let view_eye: cgmath::Point3<f32> = cgmath::Point3::new(0.0, 2.0, -2.0);
    let view_center: cgmath::Point3<f32> = cgmath::Point3::new(0.0, 0.0, 0.0);
    let view_up: cgmath::Vector3<f32> = cgmath::Vector3::new(0.0, 1.0, 0.0);
    let view_matrix: cgmath::Matrix4<f32> = cgmath::Matrix4::look_at(&view_eye, &view_center, &view_up);
    let fixed_view_matrix = view_matrix.as_fixed();
    let model_matrix: cgmath::Matrix4<f32> = cgmath::Matrix4::identity();
    let fixed_model_matrix = model_matrix.as_fixed();

    let lights = [
        Light {
            position: [1.0, 1.0, 1.0, 1.0],
            attenuation: [0.8, 0.00125, 0.0000001],
            color: [1.0, 0.0, 0.0],
            radius: 1.5
        },
        Light {
            position: [0.0, 1.0, 0.0, 1.0],
            attenuation: [0.8, 0.00125, 0.0000001],
            color: [0.0, 1.0, 0.0],
            radius: 1.5
        },
        Light {
            position: [0.0, 1.0, 1.0, 1.0],
            attenuation: [0.8, 0.00125, 0.0000001],
            color: [0.0, 0.0, 1.0],
            radius: 1.5
        },
        Light {
            position: [1.0, 1.0, 0.0, 1.0],
            attenuation: [0.8, 0.00125, 0.0000001],
            color: [1.0, 1.0, 0.0],
            radius: 1.5
        }
    ];

    // the main loop
    // each cycle will draw once
    'main: loop {
        use std::old_io::timer;
        use std::time::Duration;

        // prepass
        let uniforms = PrepassUniforms {
            perspective_matrix: *fixed_perspective_matrix,
            view_matrix: *fixed_view_matrix,
            model_matrix: *fixed_model_matrix,
            texture: &opengl_texture
        };
        framebuffer.clear_color(0.0, 0.0, 0.0, 0.0);
        framebuffer.draw(&floor_vertex_buffer, &floor_index_buffer, &prepass_program, &uniforms, &std::default::Default::default()).unwrap();

        // lighting
        let draw_params = glium::DrawParameters {
            //depth_function: glium::DepthFunction::IfLessOrEqual,
            blending_function: Some(glium::BlendingFunction::Addition{
                source: glium::LinearBlendingFactor::One,
                destination: glium::LinearBlendingFactor::One
            }),
            .. std::default::Default::default()
        };
        light_buffer.clear_color(0.0, 0.0, 0.0, 0.0);
        for light in lights.iter() {
            let uniforms = LightingUniforms {
                matrix: *fixed_ortho_matrix,
                position_texture: &texture1,
                normal_texture: &texture2,
                light_position: light.position,
                light_attenuation: light.attenuation,
                light_color: light.color,
                light_radius: light.radius
            };
            light_buffer.draw(&quad_vertex_buffer, &quad_index_buffer, &lighting_program, &uniforms, &draw_params).unwrap();
        }

        // composition
        let uniforms = CompositionUniforms {
            matrix: *fixed_ortho_matrix,
            decal_texture: &texture3,
            lighting_texture: &light_texture
        };
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.draw(&quad_vertex_buffer, &quad_index_buffer, &composition_program, &uniforms, &std::default::Default::default()).unwrap();
        target.finish();

        // sleeping for some time in order not to use up too much CPU
        timer::sleep(Duration::milliseconds(17));

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => break 'main,
                _ => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use structopt::StructOpt;

use crate::backend::BackendOpts;
use crate::transport::cw310::CW310;
use crate::transport::Transport;

#[derive(Debug, StructOpt)]
pub struct Cw310Opts {
    #[structopt(
        long,
        help = "Comma-separated list of CW310 UARTs for non-udev environments. List the console uart first."
    )]
    pub cw310_uarts: Option<String>,
}

pub fn create(args: &BackendOpts) -> Result<Box<dyn Transport>> {
    let uarts = args
        .cw310_opts
        .cw310_uarts
        .as_ref()
        .map(|v| v.split(',').collect::<Vec<&str>>())
        .unwrap_or(Vec::new());
    Ok(Box::new(CW310::new(
        args.usb_vid,
        args.usb_vid,
        args.usb_serial.as_deref(),
        &uarts,
    )?))
}
<commit_msg>[opentitantool] Fix typo in CW310 backend<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use structopt::StructOpt;

use crate::backend::BackendOpts;
use crate::transport::cw310::CW310;
use crate::transport::Transport;

#[derive(Debug, StructOpt)]
pub struct Cw310Opts {
    #[structopt(
        long,
        help = "Comma-separated list of CW310 UARTs for non-udev environments. List the console uart first."
    )]
    pub cw310_uarts: Option<String>,
}

pub fn create(args: &BackendOpts) -> Result<Box<dyn Transport>> {
    let uarts = args
        .cw310_opts
        .cw310_uarts
        .as_ref()
        .map(|v| v.split(',').collect::<Vec<&str>>())
        .unwrap_or(Vec::new());
    Ok(Box::new(CW310::new(
        args.usb_vid,
        args.usb_pid,
        args.usb_serial.as_deref(),
        &uarts,
    )?))
}
<|endoftext|>