<commit_before>/// UNIX implementation of dynamic library loading.
///
/// This module should eventually be expanded with more UNIX-specific functionality in the future.
use util::{CowCString, CStringAsRef};

use std::ffi::{CStr, OsStr};
use std::{fmt, io, marker, mem, ptr};
use std::os::raw;
use std::os::unix::ffi::OsStrExt;
use std::sync::Mutex;

lazy_static! {
    static ref DLERROR_MUTEX: Mutex<()> = Mutex::new(());
}

// libdl is crazy.
//
// First of all, whole error handling scheme in libdl is done via setting and querying some global
// state, therefore it is not safe to use libdl in MT-capable environment at all. Only in POSIX
// 2008+TC1 a thread-local state was allowed, which for our purposes is way too late.
fn with_dlerror<T, F>(closure: F) -> Result<T, Option<io::Error>>
where F: FnOnce() -> Option<T> {
    // We will guard all uses of libdl library with our own mutex. This makes libdl
    // safe to use in MT programs provided the only way a program uses libdl is via this library.
    let _lock = DLERROR_MUTEX.lock();
    // While we could could call libdl here to clear the previous error value, only the dlsym
    // depends on it being cleared beforehand and only in some cases too. We will instead clear the
    // error inside the dlsym binding instead.
    //
    // In all the other cases, clearing the error here will only be hiding misuse of these bindings
    // or the libdl.
    closure().ok_or_else(|| unsafe {
        // This code will only get executed if the `closure` returns `None`.
        let error = dlerror();
        if error.is_null() {
            // In non-dlsym case this may happen when there’s bugs in our bindings or there’s
            // non-libloading user of libdl; possibly in another thread.
            None
        } else {
            // You can’t even rely on error string being static here; call to subsequent dlerror
            // may invalidate or overwrite the error message. Why couldn’t they simply give up the
            // ownership over the message?
            // TODO: should do locale-aware conversion here. OTOH Rust doesn’t seem to work well in
            // any system that uses non-utf8 locale, so I doubt there’s a problem here.
            let message = CStr::from_ptr(error).to_string_lossy().into_owned();
            Some(io::Error::new(io::ErrorKind::Other, message))
            // Since we do a copy of the error string above, maybe we should call dlerror again to
            // let libdl know it may free its copy of the string now?
        }
    })
}

/// A platform-specific equivalent of the cross-platform `Library`.
pub struct Library {
    handle: *mut raw::c_void
}

unsafe impl ::std::marker::Send for Library {}

impl Library {
    fn open<P>(filename: Option<P>, flags: raw::c_int) -> ::Result<Library>
    where P: AsRef<OsStr> {
        let filename = match filename {
            None => None,
            Some(ref f) => Some(try!(CowCString::from_bytes(f.as_ref().as_bytes()))),
        };
        with_dlerror(move || {
            let result = unsafe {
                let r = dlopen(match filename {
                    None => ptr::null(),
                    Some(ref f) => f.cstring_ref()
                }, flags);
                // ensure filename livess until dlopen completes
                drop(filename);
                r
            };
            if result.is_null() {
                None
            } else {
                Some(Library {
                    handle: result
                })
            }
        }).map_err(|e| e.unwrap_or_else(||
            panic!("dlopen failed but dlerror did not report anything")
        ))
    }

    /// Find and load a shared library (module).
    ///
    /// Locations where library is searched for is platform specific and can’t be adjusted
    /// portably.
    ///
    /// Corresponds to `dlopen(filename)`.
    #[inline]
    pub fn new<P: AsRef<OsStr>>(filename: P) -> ::Result<Library> {
        Library::open(Some(filename), RTLD_LAZY)
    }

    /// Load the dynamic libraries linked into main program.
    ///
    /// This allows retrieving symbols from any **dynamic** library linked into the program,
    /// without specifying the exact library.
    ///
    /// Corresponds to `dlopen(NULL)`.
    #[inline]
    pub fn this() -> Library {
        Library::open(None::<&OsStr>, RTLD_NOW).unwrap()
    }

    /// Get a symbol by name.
    ///
    /// Mangling or symbol rustification is not done: trying to `get` something like `x::y`
    /// will not work.
    ///
    /// You may append a null byte at the end of the byte string to avoid string allocation in some
    /// cases. E.g. for symbol `sin` you may write `b"sin\0"` instead of `b"sin"`.
    ///
    /// # Unsafety
    ///
    /// Symbol of arbitrary requested type is returned. Using a symbol with wrong type is not
    /// memory safe.
    pub unsafe fn get<T>(&self, symbol: &[u8]) -> ::Result<Symbol<T>> {
        let symbol = try!(CowCString::from_bytes(symbol));
        // `dlsym` may return nullptr in two cases: when a symbol genuinely points to a null
        // pointer or the symbol cannot be found. In order to detect this case a double dlerror
        // pattern must be used, which is, sadly, a little bit racy.
        //
        // We try to leave as little space as possible for this to occur, but we can’t exactly
        // fully prevent it.
        match with_dlerror(|| {
            dlerror();
            let symbol = dlsym(self.handle, symbol.cstring_ref());
            if symbol.is_null() {
                None
            } else {
                Some(Symbol {
                    pointer: symbol,
                    pd: marker::PhantomData
                })
            }
        }) {
            Err(None) => Ok(Symbol {
                pointer: ptr::null_mut(),
                pd: marker::PhantomData
            }),
            Err(Some(e)) => Err(e),
            Ok(x) => Ok(x)
        }
    }
}

impl Drop for Library {
    fn drop(&mut self) {
        with_dlerror(|| if unsafe { dlclose(self.handle) } == 0 {
            Some(())
        } else {
            None
        }).unwrap();
    }
}

impl fmt::Debug for Library {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&format!("Library@{:p}", self.handle))
    }
}

/// Symbol from a library.
///
/// A major difference compared to the cross-platform `Symbol` is that this does not ensure the
/// `Symbol` does not outlive `Library` it comes from.
#[derive(Clone)]
pub struct Symbol<T> {
    pointer: *mut raw::c_void,
    pd: marker::PhantomData<T>
}

impl<T> ::std::ops::Deref for Symbol<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe {
            // Additional reference level for a dereference on `deref` return value.
            mem::transmute(&self.pointer)
        }
    }
}

impl<T> fmt::Debug for Symbol<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let mut info: DlInfo = mem::uninitialized();
            if dladdr(self.pointer, &mut info) != 0 {
                if info.dli_sname.is_null() {
                    f.write_str(&format!("Symbol@{:p} from {:?}",
                                         self.pointer,
                                         CStr::from_ptr(info.dli_fname)))
                } else {
                    f.write_str(&format!("Symbol {:?}@{:p} from {:?}",
                                         CStr::from_ptr(info.dli_sname), self.pointer,
                                         CStr::from_ptr(info.dli_fname)))
                }
            } else {
                f.write_str(&format!("Symbol@{:p}", self.pointer))
            }
        }
    }
}

// Platform specific things

extern {
    fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void;
    fn dlclose(handle: *mut raw::c_void) -> raw::c_int;
    fn dlsym(handle: *mut raw::c_void, symbol: *const raw::c_char) -> *mut raw::c_void;
    fn dlerror() -> *mut raw::c_char;
    fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int;
}

const RTLD_LAZY: raw::c_int = 1;
const RTLD_NOW: raw::c_int = 2;

#[repr(C)]
struct DlInfo {
  dli_fname: *const raw::c_char,
  dli_fbase: *mut raw::c_void,
  dli_sname: *const raw::c_char,
  dli_saddr: *mut raw::c_void
}

#[test]
fn this() {
    Library::this();
}
<commit_msg>[android] Fix RTDL_NOW constant value<commit_after>/// UNIX implementation of dynamic library loading.
///
/// This module should eventually be expanded with more UNIX-specific functionality in the future.
use util::{CowCString, CStringAsRef};

use std::ffi::{CStr, OsStr};
use std::{fmt, io, marker, mem, ptr};
use std::os::raw;
use std::os::unix::ffi::OsStrExt;
use std::sync::Mutex;

lazy_static! {
    static ref DLERROR_MUTEX: Mutex<()> = Mutex::new(());
}

// libdl is crazy.
//
// First of all, whole error handling scheme in libdl is done via setting and querying some global
// state, therefore it is not safe to use libdl in MT-capable environment at all. Only in POSIX
// 2008+TC1 a thread-local state was allowed, which for our purposes is way too late.
fn with_dlerror<T, F>(closure: F) -> Result<T, Option<io::Error>>
where F: FnOnce() -> Option<T> {
    // We will guard all uses of libdl library with our own mutex. This makes libdl
    // safe to use in MT programs provided the only way a program uses libdl is via this library.
    let _lock = DLERROR_MUTEX.lock();
    // While we could could call libdl here to clear the previous error value, only the dlsym
    // depends on it being cleared beforehand and only in some cases too. We will instead clear the
    // error inside the dlsym binding instead.
    //
    // In all the other cases, clearing the error here will only be hiding misuse of these bindings
    // or the libdl.
    closure().ok_or_else(|| unsafe {
        // This code will only get executed if the `closure` returns `None`.
        let error = dlerror();
        if error.is_null() {
            // In non-dlsym case this may happen when there’s bugs in our bindings or there’s
            // non-libloading user of libdl; possibly in another thread.
            None
        } else {
            // You can’t even rely on error string being static here; call to subsequent dlerror
            // may invalidate or overwrite the error message. Why couldn’t they simply give up the
            // ownership over the message?
            // TODO: should do locale-aware conversion here. OTOH Rust doesn’t seem to work well in
            // any system that uses non-utf8 locale, so I doubt there’s a problem here.
            let message = CStr::from_ptr(error).to_string_lossy().into_owned();
            Some(io::Error::new(io::ErrorKind::Other, message))
            // Since we do a copy of the error string above, maybe we should call dlerror again to
            // let libdl know it may free its copy of the string now?
        }
    })
}

/// A platform-specific equivalent of the cross-platform `Library`.
pub struct Library {
    handle: *mut raw::c_void
}

unsafe impl ::std::marker::Send for Library {}

impl Library {
    fn open<P>(filename: Option<P>, flags: raw::c_int) -> ::Result<Library>
    where P: AsRef<OsStr> {
        let filename = match filename {
            None => None,
            Some(ref f) => Some(try!(CowCString::from_bytes(f.as_ref().as_bytes()))),
        };
        with_dlerror(move || {
            let result = unsafe {
                let r = dlopen(match filename {
                    None => ptr::null(),
                    Some(ref f) => f.cstring_ref()
                }, flags);
                // ensure filename livess until dlopen completes
                drop(filename);
                r
            };
            if result.is_null() {
                None
            } else {
                Some(Library {
                    handle: result
                })
            }
        }).map_err(|e| e.unwrap_or_else(||
            panic!("dlopen failed but dlerror did not report anything")
        ))
    }

    /// Find and load a shared library (module).
    ///
    /// Locations where library is searched for is platform specific and can’t be adjusted
    /// portably.
    ///
    /// Corresponds to `dlopen(filename)`.
    #[inline]
    pub fn new<P: AsRef<OsStr>>(filename: P) -> ::Result<Library> {
        Library::open(Some(filename), RTLD_LAZY)
    }

    /// Load the dynamic libraries linked into main program.
    ///
    /// This allows retrieving symbols from any **dynamic** library linked into the program,
    /// without specifying the exact library.
    ///
    /// Corresponds to `dlopen(NULL)`.
    #[inline]
    pub fn this() -> Library {
        Library::open(None::<&OsStr>, RTLD_NOW).unwrap()
    }

    /// Get a symbol by name.
    ///
    /// Mangling or symbol rustification is not done: trying to `get` something like `x::y`
    /// will not work.
    ///
    /// You may append a null byte at the end of the byte string to avoid string allocation in some
    /// cases. E.g. for symbol `sin` you may write `b"sin\0"` instead of `b"sin"`.
    ///
    /// # Unsafety
    ///
    /// Symbol of arbitrary requested type is returned. Using a symbol with wrong type is not
    /// memory safe.
    pub unsafe fn get<T>(&self, symbol: &[u8]) -> ::Result<Symbol<T>> {
        let symbol = try!(CowCString::from_bytes(symbol));
        // `dlsym` may return nullptr in two cases: when a symbol genuinely points to a null
        // pointer or the symbol cannot be found. In order to detect this case a double dlerror
        // pattern must be used, which is, sadly, a little bit racy.
        //
        // We try to leave as little space as possible for this to occur, but we can’t exactly
        // fully prevent it.
        match with_dlerror(|| {
            dlerror();
            let symbol = dlsym(self.handle, symbol.cstring_ref());
            if symbol.is_null() {
                None
            } else {
                Some(Symbol {
                    pointer: symbol,
                    pd: marker::PhantomData
                })
            }
        }) {
            Err(None) => Ok(Symbol {
                pointer: ptr::null_mut(),
                pd: marker::PhantomData
            }),
            Err(Some(e)) => Err(e),
            Ok(x) => Ok(x)
        }
    }
}

impl Drop for Library {
    fn drop(&mut self) {
        with_dlerror(|| if unsafe { dlclose(self.handle) } == 0 {
            Some(())
        } else {
            None
        }).unwrap();
    }
}

impl fmt::Debug for Library {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&format!("Library@{:p}", self.handle))
    }
}

/// Symbol from a library.
///
/// A major difference compared to the cross-platform `Symbol` is that this does not ensure the
/// `Symbol` does not outlive `Library` it comes from.
#[derive(Clone)]
pub struct Symbol<T> {
    pointer: *mut raw::c_void,
    pd: marker::PhantomData<T>
}

impl<T> ::std::ops::Deref for Symbol<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe {
            // Additional reference level for a dereference on `deref` return value.
            mem::transmute(&self.pointer)
        }
    }
}

impl<T> fmt::Debug for Symbol<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            let mut info: DlInfo = mem::uninitialized();
            if dladdr(self.pointer, &mut info) != 0 {
                if info.dli_sname.is_null() {
                    f.write_str(&format!("Symbol@{:p} from {:?}",
                                         self.pointer,
                                         CStr::from_ptr(info.dli_fname)))
                } else {
                    f.write_str(&format!("Symbol {:?}@{:p} from {:?}",
                                         CStr::from_ptr(info.dli_sname), self.pointer,
                                         CStr::from_ptr(info.dli_fname)))
                }
            } else {
                f.write_str(&format!("Symbol@{:p}", self.pointer))
            }
        }
    }
}

// Platform specific things

extern {
    fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void;
    fn dlclose(handle: *mut raw::c_void) -> raw::c_int;
    fn dlsym(handle: *mut raw::c_void, symbol: *const raw::c_char) -> *mut raw::c_void;
    fn dlerror() -> *mut raw::c_char;
    fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int;
}

const RTLD_LAZY: raw::c_int = 1;
#[cfg(not(target_os="android"))]
const RTLD_NOW: raw::c_int = 2;
#[cfg(target_os="android")]
const RTLD_NOW: raw::c_int = 0;

#[repr(C)]
struct DlInfo {
  dli_fname: *const raw::c_char,
  dli_fbase: *mut raw::c_void,
  dli_sname: *const raw::c_char,
  dli_saddr: *mut raw::c_void
}

#[test]
fn this() {
    Library::this();
}
<|endoftext|>


<commit_before>mod pkg;
pub mod update;
pub mod find;<commit_msg>Add version.rs to mod.rs<commit_after>mod pkg;
pub mod update;
pub mod find;
pub mod version;<|endoftext|>


<commit_before>
use argparse;
use amqp::{ConsumerCallBackFn, Session, Table, Basic, Channel, Consumer};
use amqp::protocol;
use std::default::Default;
use rustc_serialize::json;
use std::slice;

#[derive(Debug, Default, RustcDecodable, RustcEncodable, Clone)]
pub struct Port {
    pub id: String, // port name
    pub queue: String, // the associated message queue
    // FIXME: support. Is a keyword so needs some special handling   type: String, // datatype, ex: "boolean"
    // options: queue options as specified by the message queue implementation
    // description?? TODO: standardize
}

#[derive(Debug, Default, RustcDecodable, RustcEncodable, Clone)]
pub struct Info {
    pub id: String, // unique name
    pub role: String ,// role participant has
    pub component: String, // component the participant is instance of
    pub label: Option<String>, // (optional) short human-readable description
    pub icon: Option<String>, // (optional)
    pub inports: Vec<Port>,
    pub outports: Vec<Port>,
}

pub struct InfoBuilder {
    info: Info
}

impl InfoBuilder {
    pub fn new(component: &str) -> InfoBuilder {
        InfoBuilder {
            info:  Info { component: component.to_string(),  .. Default::default() }
        }
    }

    pub fn label(&mut self, label: &str) -> &mut InfoBuilder {
        self.info.label = Some(label.to_string());
        self
    }

    pub fn role(&mut self, role: &str) -> &mut InfoBuilder {
        self.info.role = role.to_string();
        self
    }

    pub fn inport(&mut self, id: &str) -> &mut InfoBuilder {
        let port = Port { id: id.to_string(), queue: "".to_string() };
        self.info.inports.push(port);
        self
    }
    pub fn outport(&mut self, id: &str) -> &mut InfoBuilder {
        let port = Port { id: id.to_string(), queue: "".to_string() };
        self.info.outports.push(port);
        self
    }
    pub fn build(&self) -> Info {
        return self.info.clone();
    }
}

pub trait Participant : Sync {
    fn info(&self) -> Info;
    fn process(&self, Vec<u8>) -> Result<Vec<u8>, Vec<u8>>;
}

struct ParticipantData {
    info: Info,
    _trait: & 'static Participant,
}

struct Connection {
    session: Session,
    channel: Channel,
}

// FIXME: wrap in protocol/command/payload envelope
fn create_queue_and_send(channel: &mut Channel, queue_name: &str, payload: String) {

    let queue_declare = channel.queue_declare(queue_name, false, true, false, false, false, Table::new());
    queue_declare.expect("queue creation failed");
    let content_type = Some("application/json".to_string());
    let props = protocol::basic::BasicProperties { content_type: content_type, ..Default::default() };
    debug!("sending on {}: {}", queue_name, payload);
    let res = channel.basic_publish("", queue_name, true, false, props, payload.into_bytes());
    res.expect("send on new queue failed");
}

fn send_discovery(channel: &mut Channel, info: &Info) {
    let queue_name = "fbp"; // TODO: use an exchange istead, requires protocol change in msgflo

    let payload = json::encode(&info).unwrap();
    create_queue_and_send(channel, queue_name, payload);
    info!("sent participant discovery: {}  {}({})", info.id, info.role, info.component);
}

struct PortConsumer {
    participant: & 'static Participant,
    portname: String,
    outqueue: String, // FIXME: allow sending on any port, also multiple times
}

//unsafe impl Sync for PortConsumer {}
//unsafe impl Send for ParticipantTrait {}
//unsafe impl Sync for ParticipantTrait {}

fn send_out(channel: &mut Channel, exchange: String, data: Vec<u8>) {

    let routing_key = "".to_string();
    let content_type = Some("application/json".to_string()); // TODO: should be parameter
    let props = protocol::basic::BasicProperties { content_type: content_type, ..Default::default() };
    let s = channel.basic_publish(exchange, routing_key, true, false, props, data);
    s.expect("failed to send");
    debug!("sent output");
}

impl Consumer for PortConsumer {
    fn handle_delivery(&mut self,
                       channel: &mut Channel,
                       deliver: protocol::basic::Deliver,
                       headers: protocol::basic::BasicProperties,
                       body: Vec<u8>) {

        debug!("calling process()");
        let res = self.participant.process(body);
        debug!("process() returned");

        if res.is_ok() {
            debug!("ACKing and sending");
            send_out(channel, self.outqueue.to_string(), res.unwrap());
            let r = channel.basic_ack(deliver.delivery_tag, false);
        } else {
            error!("process() errored");
            let r = channel.basic_nack(deliver.delivery_tag, true, true);
        }
        // FIXME: send error data
    }
}

// FIXME: actually call ProcessFunction
fn setup_inport(participant: &ParticipantData, port: &Port, connection: &mut Connection) {
    debug!("setup inport: {}", port.queue.to_string());

    let consumer = PortConsumer {
        participant: participant._trait,
        portname: port.id.to_string(),
        outqueue: participant.info.outports[0].queue.to_string(),
    };

    // create
    let declare = connection.channel.queue_declare(port.queue.to_string(), false, true, false, false, false, Table::new());
    declare.expect("inport queue creation failed");

    // subscribe
    let q = port.queue.to_string();
    let cons = connection.channel.basic_consume(consumer, q,
                                                "".to_string(), false, false, false, false, Table::new());

    cons.expect("iport setup failed");

    debug!("inport setup done: {:?}, {:?}", port.id.to_string(), port.queue.to_string());
}

fn setup_outport(participant: &ParticipantData, port: &Port, connection: &mut Connection) {

    let exchange_type = "fanout".to_string();
    let declare = connection.channel.exchange_declare(port.queue.to_string(), exchange_type,
                                                    false, true, false, false, false, Table::new());
    declare.expect("outport setup failed");

    debug!("setup outport done: {:?}, {:?}", port.id.to_string(), port.queue.to_string());
}

fn start_participant(participant: &ParticipantData, options: &Options) -> Connection {

    let mut session = Session::open_url(&options.broker).expect("Can't create AMQP session");
    let mut channel = session.open_channel(1).expect("could not open AMQP channel");

    let mut conn = Connection { session: session, channel: channel };
    let info = &participant.info;

    // setup ports
    setup_inport(&participant, &info.inports[0], &mut conn);
    setup_outport(&participant, &info.outports[0], &mut conn);

    // send MsgFlo participant discovery message
    send_discovery(&mut conn.channel, info);

    return conn;
}

fn stop_participant(participant: &ParticipantData, connection: &mut Connection) {

    let closed = connection.channel.close(200, "Bye".to_string());
    connection.session.close(200, "Good Bye".to_string());
}

#[derive(Debug)]
struct Options {
    role: String,
    broker: String,
}

impl Default for Options {
    fn default() -> Options {

        Options {
            broker: "amqp://localhost//".to_string(),
            role: "".to_string(),
        }
    }
}

fn normalize_info(old: &Info, options: &Options) -> Info {
    use rand::{thread_rng, Rng};

    let mut new = old.clone();

    // normalize role name
    if options.role != "" {
        new.role = options.role.to_string();
    }
    if new.role == "" {
        let role_rnd: String = thread_rng().gen_ascii_chars().take(5).collect();
        new.role = format!("msgflo-rust-{}", role_rnd);
    }

    // generate ID
    let id_rnd: String = thread_rng().gen_ascii_chars().take(5).collect();
    new.id = format!("{}-{}", new.role, id_rnd);

    // generate port defaults
    let role = new.role.to_string(); // NOTE: would be nice to be able to pass reference to info?
    let normalize_port = | o: &Port | -> Port {
        let mut p = o.clone();
        if p.queue == "" {
            p.queue = default_queue(role.to_string(), p.id.to_string());
        }
        return p;
    };
    new.inports = old.inports.iter().map(&normalize_port).collect();
    new.outports = old.outports.iter().map(&normalize_port).collect();

    return new;
}

fn default_queue(role: String, port_name: String) -> String {
    return format!("{}.{}", role, port_name.to_uppercase());
}

fn parse(options: &mut Options) {

    use argparse::{StoreTrue, Store};
    let mut parser = argparse::ArgumentParser::new();

    parser.refer(&mut options.role)
        .add_option(&["--role"], Store, "Participant role name");
    parser.refer(&mut options.broker)
        .add_option(&["--broker"], Store, "Address of messaging broker")
        .envvar("MSGFLO_BROKER");

    parser.parse_args_or_exit(); // XXX: should return out
}

// XXX: seems rust-amqp makes program hangs forever if error occurs / channel is borked?
// TODO: pass port info in/out of process()
// TODO: nicer way to declare ports? ideally they are enums not stringly typed?
pub fn main(orig: & 'static Participant) {

    let mut options = Options { .. Default::default() };
    parse(&mut options);

    let i : Info = orig.info();
    let info = normalize_info(&i, &options);

    let p = ParticipantData { info: info, _trait: orig }; // XXX: hack

    let mut c = start_participant(&p, &options);

    println!("{}({}) started", p.info.role, p.info.component);
    c.channel.start_consuming();

    stop_participant(&p, &mut c);
}

<commit_msg>Remove some superflous 'static<commit_after>
use argparse;
use amqp::{ConsumerCallBackFn, Session, Table, Basic, Channel, Consumer};
use amqp::protocol;
use std::default::Default;
use rustc_serialize::json;
use std::slice;

#[derive(Debug, Default, RustcDecodable, RustcEncodable, Clone)]
pub struct Port {
    pub id: String, // port name
    pub queue: String, // the associated message queue
    // FIXME: support. Is a keyword so needs some special handling   type: String, // datatype, ex: "boolean"
    // options: queue options as specified by the message queue implementation
    // description?? TODO: standardize
}

#[derive(Debug, Default, RustcDecodable, RustcEncodable, Clone)]
pub struct Info {
    pub id: String, // unique name
    pub role: String ,// role participant has
    pub component: String, // component the participant is instance of
    pub label: Option<String>, // (optional) short human-readable description
    pub icon: Option<String>, // (optional)
    pub inports: Vec<Port>,
    pub outports: Vec<Port>,
}

pub struct InfoBuilder {
    info: Info
}

impl InfoBuilder {
    pub fn new(component: &str) -> InfoBuilder {
        InfoBuilder {
            info:  Info { component: component.to_string(),  .. Default::default() }
        }
    }

    pub fn label(&mut self, label: &str) -> &mut InfoBuilder {
        self.info.label = Some(label.to_string());
        self
    }

    pub fn role(&mut self, role: &str) -> &mut InfoBuilder {
        self.info.role = role.to_string();
        self
    }

    pub fn inport(&mut self, id: &str) -> &mut InfoBuilder {
        let port = Port { id: id.to_string(), queue: "".to_string() };
        self.info.inports.push(port);
        self
    }
    pub fn outport(&mut self, id: &str) -> &mut InfoBuilder {
        let port = Port { id: id.to_string(), queue: "".to_string() };
        self.info.outports.push(port);
        self
    }
    pub fn build(&self) -> Info {
        return self.info.clone();
    }
}

pub trait Participant : Sync {
    fn info(&self) -> Info;
    fn process(&self, Vec<u8>) -> Result<Vec<u8>, Vec<u8>>;
}

struct ParticipantData {
    info: Info,
    _trait: & 'static Participant,
}

struct Connection {
    session: Session,
    channel: Channel,
}

// FIXME: wrap in protocol/command/payload envelope
fn create_queue_and_send(channel: &mut Channel, queue_name: &str, payload: String) {

    let queue_declare = channel.queue_declare(queue_name, false, true, false, false, false, Table::new());
    queue_declare.expect("queue creation failed");
    let content_type = Some("application/json".to_string());
    let props = protocol::basic::BasicProperties { content_type: content_type, ..Default::default() };
    debug!("sending on {}: {}", queue_name, payload);
    let res = channel.basic_publish("", queue_name, true, false, props, payload.into_bytes());
    res.expect("send on new queue failed");
}

fn send_discovery(channel: &mut Channel, info: &Info) {
    let queue_name = "fbp"; // TODO: use an exchange istead, requires protocol change in msgflo

    let payload = json::encode(&info).unwrap();
    create_queue_and_send(channel, queue_name, payload);
    info!("sent participant discovery: {}  {}({})", info.id, info.role, info.component);
}

struct PortConsumer <'a> {
    participant: & 'a Participant,
    portname: String,
    outqueue: String, // FIXME: allow sending on any port, also multiple times
}

//unsafe impl Sync for PortConsumer {}
//unsafe impl Send for ParticipantTrait {}
//unsafe impl Sync for ParticipantTrait {}

fn send_out(channel: &mut Channel, exchange: String, data: Vec<u8>) {

    let routing_key = "".to_string();
    let content_type = Some("application/json".to_string()); // TODO: should be parameter
    let props = protocol::basic::BasicProperties { content_type: content_type, ..Default::default() };
    let s = channel.basic_publish(exchange, routing_key, true, false, props, data);
    s.expect("failed to send");
    debug!("sent output");
}

impl <'a>Consumer for PortConsumer<'a> {
    fn handle_delivery(&mut self,
                       channel: &mut Channel,
                       deliver: protocol::basic::Deliver,
                       headers: protocol::basic::BasicProperties,
                       body: Vec<u8>) {

        debug!("calling process()");
        let res = self.participant.process(body);
        debug!("process() returned");

        if res.is_ok() {
            debug!("ACKing and sending");
            send_out(channel, self.outqueue.to_string(), res.unwrap());
            let r = channel.basic_ack(deliver.delivery_tag, false);
        } else {
            error!("process() errored");
            let r = channel.basic_nack(deliver.delivery_tag, true, true);
        }
        // FIXME: send error data
    }
}

// FIXME: actually call ProcessFunction
fn setup_inport(participant: &ParticipantData, port: &Port, connection: &mut Connection) {
    debug!("setup inport: {}", port.queue.to_string());

    let consumer = PortConsumer {
        participant: participant._trait,
        portname: port.id.to_string(),
        outqueue: participant.info.outports[0].queue.to_string(),
    };

    // create
    let declare = connection.channel.queue_declare(port.queue.to_string(), false, true, false, false, false, Table::new());
    declare.expect("inport queue creation failed");

    // subscribe
    let q = port.queue.to_string();
    let cons = connection.channel.basic_consume(consumer, q,
                                                "".to_string(), false, false, false, false, Table::new());

    cons.expect("iport setup failed");

    debug!("inport setup done: {:?}, {:?}", port.id.to_string(), port.queue.to_string());
}

fn setup_outport(participant: &ParticipantData, port: &Port, connection: &mut Connection) {

    let exchange_type = "fanout".to_string();
    let declare = connection.channel.exchange_declare(port.queue.to_string(), exchange_type,
                                                    false, true, false, false, false, Table::new());
    declare.expect("outport setup failed");

    debug!("setup outport done: {:?}, {:?}", port.id.to_string(), port.queue.to_string());
}

fn start_participant(participant: &ParticipantData, options: &Options) -> Connection {

    let mut session = Session::open_url(&options.broker).expect("Can't create AMQP session");
    let mut channel = session.open_channel(1).expect("could not open AMQP channel");

    let mut conn = Connection { session: session, channel: channel };
    let info = &participant.info;

    // setup ports
    setup_inport(&participant, &info.inports[0], &mut conn);
    setup_outport(&participant, &info.outports[0], &mut conn);

    // send MsgFlo participant discovery message
    send_discovery(&mut conn.channel, info);

    return conn;
}

fn stop_participant(participant: &ParticipantData, connection: &mut Connection) {

    let closed = connection.channel.close(200, "Bye".to_string());
    connection.session.close(200, "Good Bye".to_string());
}

#[derive(Debug)]
struct Options {
    role: String,
    broker: String,
}

impl Default for Options {
    fn default() -> Options {

        Options {
            broker: "amqp://localhost//".to_string(),
            role: "".to_string(),
        }
    }
}

fn normalize_info(old: &Info, options: &Options) -> Info {
    use rand::{thread_rng, Rng};

    let mut new = old.clone();

    // normalize role name
    if options.role != "" {
        new.role = options.role.to_string();
    }
    if new.role == "" {
        let role_rnd: String = thread_rng().gen_ascii_chars().take(5).collect();
        new.role = format!("msgflo-rust-{}", role_rnd);
    }

    // generate ID
    let id_rnd: String = thread_rng().gen_ascii_chars().take(5).collect();
    new.id = format!("{}-{}", new.role, id_rnd);

    // generate port defaults
    let role = new.role.to_string(); // NOTE: would be nice to be able to pass reference to info?
    let normalize_port = | o: &Port | -> Port {
        let mut p = o.clone();
        if p.queue == "" {
            p.queue = default_queue(role.to_string(), p.id.to_string());
        }
        return p;
    };
    new.inports = old.inports.iter().map(&normalize_port).collect();
    new.outports = old.outports.iter().map(&normalize_port).collect();

    return new;
}

fn default_queue(role: String, port_name: String) -> String {
    return format!("{}.{}", role, port_name.to_uppercase());
}

fn parse(options: &mut Options) {

    use argparse::{StoreTrue, Store};
    let mut parser = argparse::ArgumentParser::new();

    parser.refer(&mut options.role)
        .add_option(&["--role"], Store, "Participant role name");
    parser.refer(&mut options.broker)
        .add_option(&["--broker"], Store, "Address of messaging broker")
        .envvar("MSGFLO_BROKER");

    parser.parse_args_or_exit(); // XXX: should return out
}

// XXX: seems rust-amqp makes program hangs forever if error occurs / channel is borked?
// TODO: pass port info in/out of process()
// TODO: nicer way to declare ports? ideally they are enums not stringly typed?
pub fn main(orig: & 'static Participant) {

    let mut options = Options { .. Default::default() };
    parse(&mut options);

    let i : Info = orig.info();
    let info = normalize_info(&i, &options);

    let p = ParticipantData { info: info, _trait: orig }; // XXX: hack

    let mut c = start_participant(&p, &options);

    println!("{}({}) started", p.info.role, p.info.component);
    c.channel.start_consuming();

    stop_participant(&p, &mut c);
}

<|endoftext|>


<commit_before>
use std::iter::IntoIterator;
use std::rc::Rc;
use std::cell::RefCell;

/// A wrapper for `Rc<RefCell<I>>`, that implements the `Iterator` trait.
pub struct RcIter<I> {
    /// The boxed iterator.
    pub rciter: Rc<RefCell<I>>,
}

/// Return an iterator inside a `Rc<RefCell<_>>` wrapper.
///
/// The returned `RcIter` can be cloned, and each clone will refer back to the
/// same original iterator.
///
/// `RcIter` allows doing interesting things like using `.zip()` on an iterator with
/// itself, at the cost of runtime borrow checking.
/// (If it is not obvious: this has a performance penalty.)
///
/// Iterator element type is `Self::Item`.
///
/// ```
/// use itertools::rciter;
///
/// let mut rit = rciter(0..9);
/// let mut z = rit.clone().zip(rit.clone());
/// assert_eq!(z.next(), Some((0, 1)));
/// assert_eq!(z.next(), Some((2, 3)));
/// assert_eq!(z.next(), Some((4, 5)));
/// assert_eq!(rit.next(), Some(6));
/// assert_eq!(z.next(), Some((7, 8)));
/// assert_eq!(z.next(), None);
/// ```
///
/// **Panics** in iterator methods if a borrow error is encountered,
/// but it can only happen if the `RcIter` is reentered in for example `.next()`,
/// i.e. if it somehow participates in an “iterator knot” where it is an adaptor of itself.
pub fn rciter<I>(iterable: I) -> RcIter<I::IntoIter>
    where I: IntoIterator
{
    RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) }
}

impl<I> Clone for RcIter<I> {
    #[inline]
    fn clone(&self) -> RcIter<I> {
        RcIter { rciter: self.rciter.clone() }
    }
}

impl<A, I> Iterator for RcIter<I>
    where I: Iterator<Item = A>
{
    type Item = A;
    #[inline]
    fn next(&mut self) -> Option<A> {
        self.rciter.borrow_mut().next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        // To work sanely with other API that assume they own an iterator,
        // so it can't change in other places, we can't guarantee as much
        // in our size_hint. Other clones may drain values under our feet.
        let (_, hi) = self.rciter.borrow().size_hint();
        (0, hi)
    }
}

impl<I> DoubleEndedIterator for RcIter<I>
    where I: DoubleEndedIterator
{
    #[inline]
    fn next_back(&mut self) -> Option<I::Item> {
        self.rciter.borrow_mut().next_back()
    }
}
/// Return an iterator from `&RcIter<I>` (by simply cloning it).
impl<'a, I> IntoIterator for &'a RcIter<I>
    where I: Iterator
{
    type Item = I::Item;
    type IntoIter = RcIter<I>;

    fn into_iter(self) -> RcIter<I> {
        self.clone()
    }
}
<commit_msg>DOC: simplify rciter explanation a bit<commit_after>
use std::iter::IntoIterator;
use std::rc::Rc;
use std::cell::RefCell;

/// A wrapper for `Rc<RefCell<I>>`, that implements the `Iterator` trait.
pub struct RcIter<I> {
    /// The boxed iterator.
    pub rciter: Rc<RefCell<I>>,
}

/// Return an iterator inside a `Rc<RefCell<_>>` wrapper.
///
/// The returned `RcIter` can be cloned, and each clone will refer back to the
/// same original iterator.
///
/// `RcIter` allows doing interesting things like using `.zip()` on an iterator with
/// itself, at the cost of runtime borrow checking which may have a performance
/// penalty.
///
/// Iterator element type is `Self::Item`.
///
/// ```
/// use itertools::rciter;
///
/// let mut rit = rciter(0..9);
/// let mut z = rit.clone().zip(rit.clone());
/// assert_eq!(z.next(), Some((0, 1)));
/// assert_eq!(z.next(), Some((2, 3)));
/// assert_eq!(z.next(), Some((4, 5)));
/// assert_eq!(rit.next(), Some(6));
/// assert_eq!(z.next(), Some((7, 8)));
/// assert_eq!(z.next(), None);
/// ```
///
/// **Panics** in iterator methods if a borrow error is encountered in the
/// iterator methods. It can only happen if the `RcIter` is reentered in
/// `.next()`, i.e. if it somehow participates in an “iterator knot”
/// where it is an adaptor of itself.
pub fn rciter<I>(iterable: I) -> RcIter<I::IntoIter>
    where I: IntoIterator
{
    RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) }
}

impl<I> Clone for RcIter<I> {
    #[inline]
    fn clone(&self) -> RcIter<I> {
        RcIter { rciter: self.rciter.clone() }
    }
}

impl<A, I> Iterator for RcIter<I>
    where I: Iterator<Item = A>
{
    type Item = A;
    #[inline]
    fn next(&mut self) -> Option<A> {
        self.rciter.borrow_mut().next()
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        // To work sanely with other API that assume they own an iterator,
        // so it can't change in other places, we can't guarantee as much
        // in our size_hint. Other clones may drain values under our feet.
        let (_, hi) = self.rciter.borrow().size_hint();
        (0, hi)
    }
}

impl<I> DoubleEndedIterator for RcIter<I>
    where I: DoubleEndedIterator
{
    #[inline]
    fn next_back(&mut self) -> Option<I::Item> {
        self.rciter.borrow_mut().next_back()
    }
}

/// Return an iterator from `&RcIter<I>` (by simply cloning it).
impl<'a, I> IntoIterator for &'a RcIter<I>
    where I: Iterator
{
    type Item = I::Item;
    type IntoIter = RcIter<I>;

    fn into_iter(self) -> RcIter<I> {
        self.clone()
    }
}
<|endoftext|>


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

//! Mesh loading.
//!
//! A `Mesh` describes the geometry of an object. All or part of a `Mesh` can be drawn with a
//! single draw call. A `Mesh` consists of a series of vertices, each with a certain amount of
//! user-specified attributes. These attributes are fed into shader programs. The easiest way to
//! create a mesh is to use the `#[vertex_format]` attribute on a struct, upload them into a
//! `Buffer`, and then use `Mesh::from`.

use device;
use device::{PrimitiveType, Resources, VertexCount};
use device::attrib;
use device::handle::Buffer as BufferHandle;
use device::handle::IndexBuffer as IndexBufferHandle;

/// Describes a single attribute of a vertex buffer, including its type, name, etc.
#[derive(Clone, Debug, Hash, PartialEq)]
pub struct Attribute<R: Resources> {
    /// A name to match the shader input
    pub name: String,
    /// Vertex buffer to contain the data
    pub buffer: device::handle::RawBuffer<R>,
    /// Format of the attribute
    pub format: attrib::Format,
}

/// A trait implemented automatically for user vertex structure by
/// `#[vertex_format] attribute
#[allow(missing_docs)]
pub trait VertexFormat {
    /// Create the attributes for this type, using the given buffer.
    fn generate<R: Resources>(Option<&Self>, buffer: device::handle::RawBuffer<R>)
                -> Vec<Attribute<R>>;
}

/// Describes geometry to render.
#[derive(Clone, Debug, Hash, PartialEq)]
pub struct Mesh<R: Resources> {
    /// Number of vertices in the mesh.
    pub num_vertices: device::VertexCount,
    /// Vertex attributes to use.
    pub attributes: Vec<Attribute<R>>,
}

impl<R: Resources> Mesh<R> {
    /// Create a new mesh, which is a `TriangleList` with no attributes and `nv` vertices.
    pub fn new(nv: device::VertexCount) -> Mesh<R> {
        Mesh {
            num_vertices: nv,
            attributes: Vec::new(),
        }
    }

    /// Create a new `Mesh` from a struct that implements `VertexFormat` and a buffer.
    pub fn from_format<V: VertexFormat>(buf: BufferHandle<R, V>, nv: device::VertexCount)
                       -> Mesh<R> {
        Mesh {
            num_vertices: nv,
            attributes: VertexFormat::generate(None::<&V>, buf.raw().clone()),
        }
    }

    /// Create a new intanced `Mesh` given a vertex buffer and an instance buffer.
    pub fn from_format_instanced<V: VertexFormat, U: VertexFormat>(
                                 buf: BufferHandle<R, V>,
                                 nv: device::VertexCount,
                                 inst: BufferHandle<R, U>) -> Mesh<R> {
        let per_vertex   = VertexFormat::generate(None::<&V>, buf.raw().clone());
        let per_instance = VertexFormat::generate(None::<&U>, inst.raw().clone());

        let mut attributes = per_vertex;
        for mut at in per_instance.into_iter() {
            at.format.instance_rate = 1;
            attributes.push(at);
        }

        Mesh {
            num_vertices: nv,
            attributes: attributes,
        }
    }
}

/// Description of a subset of `Mesh` data to render.
///
/// Only vertices between `start` and `end` are rendered. The
/// source of the vertex data is dependent on the `kind` value.
///
/// The `prim_type` defines how the mesh contents are interpreted.
/// For example,  `Point` typed vertex slice can be used to do shape
/// blending, while still rendereing it as an indexed `TriangleList`.
#[derive(Clone, Debug, PartialEq)]
pub struct Slice<R: Resources> {
    /// Start index of vertices to draw.
    pub start: VertexCount,
    /// End index of vertices to draw.
    pub end: VertexCount,
    /// Primitive type to render collections of vertices as.
    pub prim_type: PrimitiveType,
    /// Source of the vertex ordering when drawing.
    pub kind: SliceKind<R>,
}

/// Source of vertex ordering for a slice
#[derive(Clone, Debug, PartialEq)]
pub enum SliceKind<R: Resources> {
    /// Render vertex data directly from the `Mesh`'s buffer.
    Vertex,
    /// The `Index*` buffer contains a list of indices into the `Mesh`
    /// data, so every vertex attribute does not need to be duplicated, only
    /// its position in the `Mesh`. The base index is added to this index
    /// before fetching the vertex from the buffer.  For example, when drawing
    /// a square, two triangles are needed.  Using only `Vertex`, one
    /// would need 6 separate vertices, 3 for each triangle. However, two of
    /// the vertices will be identical, wasting space for the duplicated
    /// attributes.  Instead, the `Mesh` can store 4 vertices and an
    /// `Index8` can be used instead.
    Index8(IndexBufferHandle<R, u8>, VertexCount),
    /// As `Index8` but with `u16` indices
    Index16(IndexBufferHandle<R, u16>, VertexCount),
    /// As `Index8` but with `u32` indices
    Index32(IndexBufferHandle<R, u32>, VertexCount),
}

/// Helper methods for cleanly getting the slice of a type.
pub trait ToSlice<R: Resources> {
    /// Get the slice of a type.
    fn to_slice(&self, pt: PrimitiveType) -> Slice<R>;
}

impl<R: Resources> ToSlice<R> for Mesh<R> {
    /// Return a vertex slice of the whole mesh.
    fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
        Slice {
            start: 0,
            end: self.num_vertices,
            prim_type: ty,
            kind: SliceKind::Vertex
        }
    }
}

impl<R: Resources> ToSlice<R> for IndexBufferHandle<R, u8> {
    /// Return an index slice of the whole buffer.
    fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
        Slice {
            start: 0,
            end: self.len() as VertexCount,
            prim_type: ty,
            kind: SliceKind::Index8(self.clone(), 0)
        }
    }
}

impl<R: Resources> ToSlice<R> for IndexBufferHandle<R, u16> {
    /// Return an index slice of the whole buffer.
    fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
        Slice {
            start: 0,
            end: self.len() as VertexCount,
            prim_type: ty,
            kind: SliceKind::Index16(self.clone(), 0)
        }
    }
}

impl<R: Resources> ToSlice<R> for IndexBufferHandle<R, u32> {
    /// Return an index slice of the whole buffer.
    fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
        Slice {
            start: 0,
            end: self.len() as VertexCount,
            prim_type: ty,
            kind: SliceKind::Index32(self.clone(), 0)
        }
    }
}

/// Index of a vertex attribute inside the mesh
pub type AttributeIndex = usize;

/// Describes kinds of errors that may occur in the mesh linking
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
    /// A required attribute was missing.
    AttributeMissing(String),
    /// An attribute's type from the vertex format differed from the type used in the shader.
    AttributeType(String, device::shade::BaseType),
    /// An attribute index is out of supported bounds
    AttributeIndex(AttributeIndex),
    /// An input index is out of supported bounds
    ShaderInputIndex(usize),
}

const BITS_PER_ATTRIBUTE: AttributeIndex = 4;
const MESH_ATTRIBUTE_MASK: AttributeIndex = (1 << BITS_PER_ATTRIBUTE) - 1;
const MAX_SHADER_INPUTS: usize = 64 / BITS_PER_ATTRIBUTE;

/// An iterator over mesh attributes.
#[derive(Copy)]
pub struct AttributeIter {
    value: u64,
}

impl Iterator for AttributeIter {
    type Item = AttributeIndex;

    fn next(&mut self) -> Option<AttributeIndex> {
        let id = (self.value as AttributeIndex) & MESH_ATTRIBUTE_MASK;
        self.value >>= BITS_PER_ATTRIBUTE;
        Some(id)
    }
}

/// Holds a remapping table from shader inputs to mesh attributes.
#[derive(Copy)]
pub struct Link {
    table: u64,
}

impl Link {
    /// Match mesh attributes against shader inputs, produce a mesh link.
    /// Exposed to public to allow external `Batch` implementations to use it.
    pub fn new<R: Resources>(mesh: &Mesh<R>, pinfo: &device::shade::ProgramInfo)
                             -> Result<Link, Error> {
        let mut indices = Vec::new();
        for sat in pinfo.attributes.iter() {
            match mesh.attributes.iter().enumerate()
                      .find(|&(_, a)| a.name == sat.name) {
                Some((attrib_id, vat)) => match vat.format.elem_type.is_compatible(sat.base_type) {
                    Ok(_) => indices.push(attrib_id),
                    Err(_) => return Err(Error::AttributeType(sat.name.clone(), sat.base_type)),
                },
                None => return Err(Error::AttributeMissing(sat.name.clone())),
            }
        }
        Link::from_iter(indices.into_iter())
    }

    /// Construct a new link from an iterator over attribute indices.
    pub fn from_iter<I: Iterator<Item = AttributeIndex>>(iter: I)
                     -> Result<Link, Error> {
        let mut table = 0u64;
        for (input, attrib) in iter.enumerate() {
            if input >= MAX_SHADER_INPUTS {
                return Err(Error::ShaderInputIndex(input))
            } else if attrib > MESH_ATTRIBUTE_MASK {
                return Err(Error::AttributeIndex(attrib))
            } else {
                table |= (attrib as u64) << (input * BITS_PER_ATTRIBUTE);
            }
        }
        Ok(Link {
            table: table,
        })
    }

    /// Convert to an iterator returning attribute indices
    pub fn to_iter(&self) -> AttributeIter {
        AttributeIter {
            value: self.table,
        }
    }
}
<commit_msg>Remove unused arg from VertexFormat::generate<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Mesh loading.
//!
//! A `Mesh` describes the geometry of an object. All or part of a `Mesh` can be drawn with a
//! single draw call. A `Mesh` consists of a series of vertices, each with a certain amount of
//! user-specified attributes. These attributes are fed into shader programs. The easiest way to
//! create a mesh is to use the `#[vertex_format]` attribute on a struct, upload them into a
//! `Buffer`, and then use `Mesh::from`.

use std::marker::PhantomFn;

use device;
use device::{PrimitiveType, Resources, VertexCount};
use device::attrib;
use device::handle::Buffer as BufferHandle;
use device::handle::IndexBuffer as IndexBufferHandle;

/// Describes a single attribute of a vertex buffer, including its type, name, etc.
#[derive(Clone, Debug, Hash, PartialEq)]
pub struct Attribute<R: Resources> {
    /// A name to match the shader input
    pub name: String,
    /// Vertex buffer to contain the data
    pub buffer: device::handle::RawBuffer<R>,
    /// Format of the attribute
    pub format: attrib::Format,
}

/// A trait implemented automatically for user vertex structure by
/// `#[vertex_format] attribute
#[allow(missing_docs)]
pub trait VertexFormat: PhantomFn<Self> {
    /// Create the attributes for this type, using the given buffer.
    fn generate<R: Resources>(buffer: device::handle::RawBuffer<R>) -> Vec<Attribute<R>>;
}

/// Describes geometry to render.
#[derive(Clone, Debug, Hash, PartialEq)]
pub struct Mesh<R: Resources> {
    /// Number of vertices in the mesh.
    pub num_vertices: device::VertexCount,
    /// Vertex attributes to use.
    pub attributes: Vec<Attribute<R>>,
}

impl<R: Resources> Mesh<R> {
    /// Create a new mesh, which is a `TriangleList` with no attributes and `nv` vertices.
    pub fn new(nv: device::VertexCount) -> Mesh<R> {
        Mesh {
            num_vertices: nv,
            attributes: Vec::new(),
        }
    }

    /// Create a new `Mesh` from a struct that implements `VertexFormat` and a buffer.
    pub fn from_format<V: VertexFormat>(buf: BufferHandle<R, V>, nv: device::VertexCount)
                       -> Mesh<R> {
        Mesh {
            num_vertices: nv,
            attributes: <V as VertexFormat>::generate(buf.raw().clone()),
        }
    }

    /// Create a new intanced `Mesh` given a vertex buffer and an instance buffer.
    pub fn from_format_instanced<V: VertexFormat, U: VertexFormat>(
                                 buf: BufferHandle<R, V>,
                                 nv: device::VertexCount,
                                 inst: BufferHandle<R, U>) -> Mesh<R> {
        let per_vertex   = <V as VertexFormat>::generate(buf.raw().clone());
        let per_instance = <U as VertexFormat>::generate(inst.raw().clone());

        let mut attributes = per_vertex;
        for mut at in per_instance.into_iter() {
            at.format.instance_rate = 1;
            attributes.push(at);
        }

        Mesh {
            num_vertices: nv,
            attributes: attributes,
        }
    }
}

/// Description of a subset of `Mesh` data to render.
///
/// Only vertices between `start` and `end` are rendered. The
/// source of the vertex data is dependent on the `kind` value.
///
/// The `prim_type` defines how the mesh contents are interpreted.
/// For example,  `Point` typed vertex slice can be used to do shape
/// blending, while still rendereing it as an indexed `TriangleList`.
#[derive(Clone, Debug, PartialEq)]
pub struct Slice<R: Resources> {
    /// Start index of vertices to draw.
    pub start: VertexCount,
    /// End index of vertices to draw.
    pub end: VertexCount,
    /// Primitive type to render collections of vertices as.
    pub prim_type: PrimitiveType,
    /// Source of the vertex ordering when drawing.
    pub kind: SliceKind<R>,
}

/// Source of vertex ordering for a slice
#[derive(Clone, Debug, PartialEq)]
pub enum SliceKind<R: Resources> {
    /// Render vertex data directly from the `Mesh`'s buffer.
    Vertex,
    /// The `Index*` buffer contains a list of indices into the `Mesh`
    /// data, so every vertex attribute does not need to be duplicated, only
    /// its position in the `Mesh`. The base index is added to this index
    /// before fetching the vertex from the buffer.  For example, when drawing
    /// a square, two triangles are needed.  Using only `Vertex`, one
    /// would need 6 separate vertices, 3 for each triangle. However, two of
    /// the vertices will be identical, wasting space for the duplicated
    /// attributes.  Instead, the `Mesh` can store 4 vertices and an
    /// `Index8` can be used instead.
    Index8(IndexBufferHandle<R, u8>, VertexCount),
    /// As `Index8` but with `u16` indices
    Index16(IndexBufferHandle<R, u16>, VertexCount),
    /// As `Index8` but with `u32` indices
    Index32(IndexBufferHandle<R, u32>, VertexCount),
}

/// Helper methods for cleanly getting the slice of a type.
pub trait ToSlice<R: Resources> {
    /// Get the slice of a type.
    fn to_slice(&self, pt: PrimitiveType) -> Slice<R>;
}

impl<R: Resources> ToSlice<R> for Mesh<R> {
    /// Return a vertex slice of the whole mesh.
    fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
        Slice {
            start: 0,
            end: self.num_vertices,
            prim_type: ty,
            kind: SliceKind::Vertex
        }
    }
}

impl<R: Resources> ToSlice<R> for IndexBufferHandle<R, u8> {
    /// Return an index slice of the whole buffer.
    fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
        Slice {
            start: 0,
            end: self.len() as VertexCount,
            prim_type: ty,
            kind: SliceKind::Index8(self.clone(), 0)
        }
    }
}

impl<R: Resources> ToSlice<R> for IndexBufferHandle<R, u16> {
    /// Return an index slice of the whole buffer.
    fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
        Slice {
            start: 0,
            end: self.len() as VertexCount,
            prim_type: ty,
            kind: SliceKind::Index16(self.clone(), 0)
        }
    }
}

impl<R: Resources> ToSlice<R> for IndexBufferHandle<R, u32> {
    /// Return an index slice of the whole buffer.
    fn to_slice(&self, ty: PrimitiveType) -> Slice<R> {
        Slice {
            start: 0,
            end: self.len() as VertexCount,
            prim_type: ty,
            kind: SliceKind::Index32(self.clone(), 0)
        }
    }
}

/// Index of a vertex attribute inside the mesh
pub type AttributeIndex = usize;

/// Describes kinds of errors that may occur in the mesh linking
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
    /// A required attribute was missing.
    AttributeMissing(String),
    /// An attribute's type from the vertex format differed from the type used in the shader.
    AttributeType(String, device::shade::BaseType),
    /// An attribute index is out of supported bounds
    AttributeIndex(AttributeIndex),
    /// An input index is out of supported bounds
    ShaderInputIndex(usize),
}

const BITS_PER_ATTRIBUTE: AttributeIndex = 4;
const MESH_ATTRIBUTE_MASK: AttributeIndex = (1 << BITS_PER_ATTRIBUTE) - 1;
const MAX_SHADER_INPUTS: usize = 64 / BITS_PER_ATTRIBUTE;

/// An iterator over mesh attributes.
#[derive(Copy)]
pub struct AttributeIter {
    value: u64,
}

impl Iterator for AttributeIter {
    type Item = AttributeIndex;

    fn next(&mut self) -> Option<AttributeIndex> {
        let id = (self.value as AttributeIndex) & MESH_ATTRIBUTE_MASK;
        self.value >>= BITS_PER_ATTRIBUTE;
        Some(id)
    }
}

/// Holds a remapping table from shader inputs to mesh attributes.
#[derive(Copy)]
pub struct Link {
    table: u64,
}

impl Link {
    /// Match mesh attributes against shader inputs, produce a mesh link.
    /// Exposed to public to allow external `Batch` implementations to use it.
    pub fn new<R: Resources>(mesh: &Mesh<R>, pinfo: &device::shade::ProgramInfo)
                             -> Result<Link, Error> {
        let mut indices = Vec::new();
        for sat in pinfo.attributes.iter() {
            match mesh.attributes.iter().enumerate()
                      .find(|&(_, a)| a.name == sat.name) {
                Some((attrib_id, vat)) => match vat.format.elem_type.is_compatible(sat.base_type) {
                    Ok(_) => indices.push(attrib_id),
                    Err(_) => return Err(Error::AttributeType(sat.name.clone(), sat.base_type)),
                },
                None => return Err(Error::AttributeMissing(sat.name.clone())),
            }
        }
        Link::from_iter(indices.into_iter())
    }

    /// Construct a new link from an iterator over attribute indices.
    pub fn from_iter<I: Iterator<Item = AttributeIndex>>(iter: I)
                     -> Result<Link, Error> {
        let mut table = 0u64;
        for (input, attrib) in iter.enumerate() {
            if input >= MAX_SHADER_INPUTS {
                return Err(Error::ShaderInputIndex(input))
            } else if attrib > MESH_ATTRIBUTE_MASK {
                return Err(Error::AttributeIndex(attrib))
            } else {
                table |= (attrib as u64) << (input * BITS_PER_ATTRIBUTE);
            }
        }
        Ok(Link {
            table: table,
        })
    }

    /// Convert to an iterator returning attribute indices
    pub fn to_iter(&self) -> AttributeIter {
        AttributeIter {
            value: self.table,
        }
    }
}
<|endoftext|>


<commit_before>use error::{Result, SassError, ErrorKind};
use evaluator::Evaluator;
use event::Event;
use top_level_event::TopLevelEvent;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use sass::mixin::{SassMixin, SassMixinParameter, SassMixinCall, SassMixinArgument};

use std::collections::HashMap;
use std::borrow::Cow::{self, Borrowed, Owned};

pub struct Substituter<'vm, I> {
    tokenizer: I,
    variables: HashMap<String, ValuePart<'vm>>,
    mixins:    HashMap<String, SassMixin<'vm>>,
}

impl<'vm, I> Substituter<'vm, I> {
    pub fn new(tokenizer: I) -> Substituter<'vm, I> {
        Substituter {
            tokenizer: tokenizer,
            variables: HashMap::new(),
            mixins:    HashMap::new(),
        }
    }
}

impl<'a, I> Iterator for Substituter<'a, I>
    where I: Iterator<Item = Result<TopLevelEvent<'a>>>
{
    type Item = Result<TopLevelEvent<'a>>;

    fn next(&mut self) -> Option<Result<TopLevelEvent<'a>>> {
        match self.tokenizer.next() {
            Some(Ok(TopLevelEvent::Variable(SassVariable { name, value }))) => {
                let val = match owned_evaluated_value(value, &self.variables) {
                    Ok(v) => v,
                    Err(e) => return Some(Err(e)),
                };
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(Ok(TopLevelEvent::Mixin(mixin))) => {
                self.mixins.insert((mixin.name).to_string(), mixin);
                self.next()
            },
            Some(Ok(TopLevelEvent::Rule(sass_rule))) => {
                let replaced = match replace_children_in_scope(
                    sass_rule.children, self.variables.clone(), self.mixins.clone()
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };

                Some(Ok(TopLevelEvent::Rule(SassRule {
                    children: replaced, ..sass_rule
                })))
            },
            Some(Ok(TopLevelEvent::MixinCall(mixin_call))) => unimplemented!(),
            other => other,
        }
    }
}

fn replace_children_in_scope<'b>(
    children: Vec<Event<'b>>,
    mut local_variables: HashMap<String, ValuePart<'b>>,
    local_mixins: HashMap<String, SassMixin<'b>>) -> Result<Vec<Event<'b>>> {

    let mut results = Vec::new();

    for c in children.into_iter() {
        match c {
            Event::Variable(SassVariable { name, value }) => {
                let val = try!(owned_evaluated_value(value, &local_variables));
                local_variables.insert((*name).to_string(), val);
            },
            Event::UnevaluatedProperty(name, value) => {
                let mut ev = Evaluator::new_from_string(&value);
                let ev_res = try!(ev.evaluate(&local_variables)).into_owned();

                results.push(Event::Property(
                    name,
                    ev_res,
                ));
            },
            Event::ChildRule(rule) => {
                let res = try!(replace_children_in_scope(
                    rule.children, local_variables.clone(), local_mixins.clone()
                ));
                results.push(Event::ChildRule(SassRule {
                    children: res, ..rule
                }));
            },
            Event::MixinCall(mixin_call) => {
                let mixin_name = mixin_call.name.into_owned();
                let mixin_definition = match local_mixins.get(&mixin_name) {
                    Some(mixin) => mixin,
                    None => return Err(SassError {
                        kind: ErrorKind::ExpectedMixin,
                        message: format!("Cannot find mixin named `{}`", mixin_name),
                    }),
                };

                let mixin_replacements = try!(collate_mixin_args(
                    &mixin_definition.parameters,
                    &mixin_call.arguments,
                ));

                let mut res = try!(replace_children_in_scope(
                    mixin_definition.children.clone(), mixin_replacements, local_mixins.clone()
                ));

                results.append(&mut res);
            },
            other => results.push(other),
        }
    }
    Ok(results)
}

fn collate_mixin_args<'a>(
    parameters: &Vec<SassMixinParameter<'a>>,
    arguments: &Vec<SassMixinArgument<'a>>) -> Result<HashMap<String, ValuePart<'a>>> {

    let mut named_arguments = HashMap::new();

    for a in arguments.iter() {
        match a.name {
            Some(ref name) => {
                named_arguments.insert(name.clone(), a.value.clone().into_owned());
            },
            None => {},
        }
    }

    let mut replacements = HashMap::new();

    for (i, p) in parameters.iter().enumerate() {
        let replacement_name = p.name.to_string();

        let replacement_value = match named_arguments.get(&p.name) {
            Some(ref value) => {
                ValuePart::String(Owned(value.to_string()))
            },
            None => {
                match arguments.get(i) {
                    Some(ref arg) => {
                        ValuePart::String(Owned(arg.value.clone().into_owned()))
                    },
                    None => {
                        match p.default {
                            Some(ref default) => {
                                ValuePart::String(Owned(default.clone().into_owned()))
                            },
                            None => {
                                return Err(SassError {
                                    kind: ErrorKind::ExpectedMixinArgument,
                                    message: format!("Cannot find argument for mixin parameter named `{}` in arguments `{:?}`", p.name, arguments),
                                })
                            }
                        }
                    },
                }
            },
        };

        replacements.insert(replacement_name, replacement_value);
    }

    Ok(replacements)
}

fn owned_evaluated_value<'a>(
    value: Cow<'a, str>,
    variables: &HashMap<String, ValuePart<'a>>) -> Result<ValuePart<'a>> {

    let value_part = match value {
        Cow::Borrowed(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables))
        },
        Cow::Owned(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables)).into_owned()
        },
    };
    Ok(match value_part {
        ValuePart::Number(nv) => ValuePart::Number(NumberValue { computed: true, ..nv }),
        other => other,
    })
}
<commit_msg>Refactor matches into .or().and_then()s<commit_after>use error::{Result, SassError, ErrorKind};
use evaluator::Evaluator;
use event::Event;
use top_level_event::TopLevelEvent;
use sass::rule::SassRule;
use sass::variable::SassVariable;
use sass::number_value::NumberValue;
use sass::value_part::ValuePart;
use sass::mixin::{SassMixin, SassMixinParameter, SassMixinCall, SassMixinArgument};

use std::collections::HashMap;
use std::borrow::Cow::{self, Borrowed, Owned};

pub struct Substituter<'vm, I> {
    tokenizer: I,
    variables: HashMap<String, ValuePart<'vm>>,
    mixins:    HashMap<String, SassMixin<'vm>>,
}

impl<'vm, I> Substituter<'vm, I> {
    pub fn new(tokenizer: I) -> Substituter<'vm, I> {
        Substituter {
            tokenizer: tokenizer,
            variables: HashMap::new(),
            mixins:    HashMap::new(),
        }
    }
}

impl<'a, I> Iterator for Substituter<'a, I>
    where I: Iterator<Item = Result<TopLevelEvent<'a>>>
{
    type Item = Result<TopLevelEvent<'a>>;

    fn next(&mut self) -> Option<Result<TopLevelEvent<'a>>> {
        match self.tokenizer.next() {
            Some(Ok(TopLevelEvent::Variable(SassVariable { name, value }))) => {
                let val = match owned_evaluated_value(value, &self.variables) {
                    Ok(v) => v,
                    Err(e) => return Some(Err(e)),
                };
                self.variables.insert((*name).to_string(), val);
                self.next()
            },
            Some(Ok(TopLevelEvent::Mixin(mixin))) => {
                self.mixins.insert((mixin.name).to_string(), mixin);
                self.next()
            },
            Some(Ok(TopLevelEvent::Rule(sass_rule))) => {
                let replaced = match replace_children_in_scope(
                    sass_rule.children, self.variables.clone(), self.mixins.clone()
                ) {
                    Ok(children) => children,
                    Err(e) => return Some(Err(e)),
                };

                Some(Ok(TopLevelEvent::Rule(SassRule {
                    children: replaced, ..sass_rule
                })))
            },
            Some(Ok(TopLevelEvent::MixinCall(mixin_call))) => unimplemented!(),
            other => other,
        }
    }
}

fn replace_children_in_scope<'b>(
    children: Vec<Event<'b>>,
    mut local_variables: HashMap<String, ValuePart<'b>>,
    local_mixins: HashMap<String, SassMixin<'b>>) -> Result<Vec<Event<'b>>> {

    let mut results = Vec::new();

    for c in children.into_iter() {
        match c {
            Event::Variable(SassVariable { name, value }) => {
                let val = try!(owned_evaluated_value(value, &local_variables));
                local_variables.insert((*name).to_string(), val);
            },
            Event::UnevaluatedProperty(name, value) => {
                let mut ev = Evaluator::new_from_string(&value);
                let ev_res = try!(ev.evaluate(&local_variables)).into_owned();

                results.push(Event::Property(
                    name,
                    ev_res,
                ));
            },
            Event::ChildRule(rule) => {
                let res = try!(replace_children_in_scope(
                    rule.children, local_variables.clone(), local_mixins.clone()
                ));
                results.push(Event::ChildRule(SassRule {
                    children: res, ..rule
                }));
            },
            Event::MixinCall(mixin_call) => {
                let mixin_name = mixin_call.name.into_owned();
                let mixin_definition = match local_mixins.get(&mixin_name) {
                    Some(mixin) => mixin,
                    None => return Err(SassError {
                        kind: ErrorKind::ExpectedMixin,
                        message: format!("Cannot find mixin named `{}`", mixin_name),
                    }),
                };

                let mixin_replacements = try!(collate_mixin_args(
                    &mixin_definition.parameters,
                    &mixin_call.arguments,
                ));

                let mut res = try!(replace_children_in_scope(
                    mixin_definition.children.clone(), mixin_replacements, local_mixins.clone()
                ));

                results.append(&mut res);
            },
            other => results.push(other),
        }
    }
    Ok(results)
}

fn collate_mixin_args<'a>(
    parameters: &Vec<SassMixinParameter<'a>>,
    arguments: &Vec<SassMixinArgument<'a>>) -> Result<HashMap<String, ValuePart<'a>>> {

    let mut named_arguments = HashMap::new();

    for a in arguments.iter() {
        match a.name {
            Some(ref name) => {
                named_arguments.insert(name.clone(), a.value.clone().into_owned());
            },
            None => {},
        }
    }

    let mut replacements = HashMap::new();

    for (i, p) in parameters.iter().enumerate() {
        let replacement_name = p.name.to_string();

        let replacement_value =
            try!(named_arguments.get(&p.name).and_then( |v| Some(v.to_string()) )
                .or(arguments.get(i).and_then( |a| Some(a.value.clone().into_owned()) ))
                .or(p.default.clone().and_then( |d| Some(d.into_owned()) ))
                .ok_or(SassError {
                    kind: ErrorKind::ExpectedMixinArgument,
                    message: format!("Cannot find argument for mixin parameter named `{}` in arguments `{:?}`", p.name, arguments),
                }));

        replacements.insert(replacement_name, ValuePart::String(Owned(replacement_value)));
    }

    Ok(replacements)
}

fn owned_evaluated_value<'a>(
    value: Cow<'a, str>,
    variables: &HashMap<String, ValuePart<'a>>) -> Result<ValuePart<'a>> {

    let value_part = match value {
        Cow::Borrowed(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables))
        },
        Cow::Owned(v) => {
            try!(Evaluator::new_from_string(&v).evaluate(variables)).into_owned()
        },
    };
    Ok(match value_part {
        ValuePart::Number(nv) => ValuePart::Number(NumberValue { computed: true, ..nv }),
        other => other,
    })
}
<|endoftext|>


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

#![allow(dead_code, unused_imports)]

extern crate gcc;

use client::connect_with_retry;
use env_logger;
use log::LogLevel::Trace;
use serde_json;
use server::ServerInfo;
use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr,OsString};
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path,PathBuf};
use std::process::{
    Command,
    Output,
    Stdio,
};
use tempdir::TempDir;
use test::utils::*;
use which::which_in;

struct Compiler {
    pub name: &'static str,
    pub exe: OsString,
    pub env_vars: Vec<(OsString, OsString)>,
}

// Test GCC + clang on non-OS X platforms.
#[cfg(all(unix, not(target_os="macos")))]
const COMPILERS: &'static [&'static str] = &["gcc", "clang"];

// OS X ships a `gcc` that's just a clang wrapper, so only test clang there.
#[cfg(target_os="macos")]
const COMPILERS: &'static [&'static str] = &["clang"];

//TODO: could test gcc when targeting mingw.

fn do_run<T: AsRef<OsStr>>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> Output {
    let mut cmd = Command::new(exe);
    cmd.args(args)
        .current_dir(cwd)
        .stdout(Stdio::piped())
        .stderr(Stdio::piped());
    for &(ref k, ref v) in env_vars.iter() {
        cmd.env(k, v);
    }
    trace!("do_run: {:?}", cmd);
    cmd.spawn()
        .unwrap_or_else(|e| { panic!("failed to execute child: {}", e) })
        .wait_with_output()
        .unwrap()
}

fn run_stdout<T>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> String
    where T: AsRef<OsStr> + fmt::Debug,
{
    let output = do_run(exe, args, cwd, env_vars);
    assert!(output.status.success(), "Failed to run {:?} {:?}", exe, args);
    String::from_utf8(output.stdout).expect("Couldn't convert stdout to String")
}

fn run<T: AsRef<OsStr>>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> bool {
    let output = do_run(exe, args, cwd, env_vars);
    if output.status.success() {
        true
    } else {
        let va = args.iter().map(|a| a.as_ref().to_str().unwrap()).collect::<Vec<_>>();
        println!("Process `{:?} {}` failed:", exe, va.join(" "));
        print!("stdout: `");
        io::stdout().write(&output.stdout).unwrap();
        println!("`");
        print!("stderr: `");
        io::stdout().write(&output.stderr).unwrap();
        println!("`");
        false
    }
}

macro_rules! vec_from {
    ( $t:ty, $( $x:expr ),* ) => {
        vec!($( Into::<$t>::into(&$x), )*)
    };
}

fn compile_cmdline<T: AsRef<OsStr>>(compiler: &str, exe: T, input: &str, output: &str) -> Vec<OsString> {
    match compiler {
        "gcc" | "clang" => vec_from!(OsString, exe.as_ref(), "-c", input, "-o", output),
        "cl.exe" => vec_from!(OsString, exe, "-c", input, format!("-Fo{}", output)),
        _ => panic!("Unsupported compiler: {}", compiler),
    }
}

fn get_stats(sccache: &Path, cwd: &Path) -> ServerInfo {
    let output = run_stdout(sccache, &["--show-stats", "--stats-format=json"], cwd, &[]);
    serde_json::from_str(&output).expect("Failed to parse JSON stats")
}

fn run_sccache_command_test(sccache: &Path, compiler: Compiler, tempdir: &Path) {
    let Compiler { name, exe, env_vars } = compiler;
    // Ensure there's no existing sccache server running.
    trace!("stop server");
    do_run(sccache, &["--stop-server"], tempdir, &[]);
    // Create a subdir for the cache.
    let cache = tempdir.join("cache");
    fs::create_dir_all(&cache).unwrap();
    // Start a server.
    trace!("start server");
    // Don't run this with run() because on Windows `wait_with_output`
    // will hang because the internal server process is not detached.
    assert!(Command::new(sccache)
            .arg("--start-server")
            .current_dir(tempdir)
            .env("SCCACHE_DIR", &cache)
            .status()
            .unwrap()
            .success());
    trace!("run_sccache_command_test: {}", name);
    // Compile a source file.
    const INPUT: &'static str = "test.c";
    const INPUT_ERR: &'static str = "test_err.c";
    const OUTPUT: &'static str = "test.o";
    // Copy the source files into the tempdir so we can compile with relative paths, since the commandline winds up in the hash key.
    for f in &[INPUT, INPUT_ERR] {
        let original_source_file = Path::new(file!()).parent().unwrap().join(f);
        let source_file = tempdir.join(f);
        trace!("fs::copy({:?}, {:?})", original_source_file, source_file);
        fs::copy(&original_source_file, &source_file).unwrap();
    }

    let out_file = tempdir.join("test.o");
    trace!("compile");
    assert_eq!(true, run(sccache, &compile_cmdline(name, &exe, INPUT, OUTPUT), tempdir, &env_vars));
    assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
    trace!("request stats");
    let info = get_stats(sccache, tempdir);
    assert_eq!(1, info.stats.compile_requests);
    assert_eq!(1, info.stats.requests_executed);
    assert_eq!(0, info.stats.cache_hits);
    assert_eq!(1, info.stats.cache_misses);
    trace!("compile");
    fs::remove_file(&out_file).unwrap();
    assert_eq!(true, run(sccache, &compile_cmdline(name, &exe, INPUT, OUTPUT), tempdir, &env_vars));
    assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
    trace!("request stats");
    let info = get_stats(sccache, tempdir);
    assert_eq!(2, info.stats.compile_requests);
    assert_eq!(2, info.stats.requests_executed);
    assert_eq!(1, info.stats.cache_hits);
    assert_eq!(1, info.stats.cache_misses);
    if name == "cl.exe" {
        // Check that -deps works.
        trace!("compile with -deps");
        let mut args = compile_cmdline(name, &exe, INPUT, OUTPUT);
        args.push("-depstest.d".into());
        assert_eq!(true, run(sccache, &args, tempdir, &env_vars));
        // Check the contents
        let mut f = File::open(tempdir.join("test.d")).expect("Failed to open dep file");
        let mut buf = String::new();
        // read_to_string should be safe because we're supplying all the filenames here,
        // and there are no absolute paths.
        f.read_to_string(&mut buf).expect("Failed to read dep file");
        let lines: Vec<_> = buf.lines().map(|l| l.trim_right()).collect();
        let expected = format!("{output}: {input}\n{input}:\n", output=OUTPUT, input=INPUT);
        let expected_lines: Vec<_> = expected.lines().collect();
        assert_eq!(lines, expected_lines);
    }
    if name == "gcc" {
        trace!("test -MP with -Werror");
        let mut args = compile_cmdline(name, &exe, INPUT_ERR, OUTPUT);
        args.extend(vec_from!(OsString, "-MD", "-MP", "-MF", "foo.pp", "-Werror"));
        let output = do_run(sccache, &args, tempdir, &env_vars);
        assert!(!output.status.success());
        // This should fail, but the error should be from the #error!
        let stderr = String::from_utf8(output.stderr).expect("Couldn't convert stderr to String");
        assert!(stderr.find("to generate dependencies you must specify either -M or -MM").is_none(), "Should not have complained about commandline arguments");
    }
    trace!("stop server");
    assert_eq!(true, run(sccache, &["--stop-server"], tempdir, &[]));
}

#[cfg(unix)]
fn find_compilers() -> Vec<Compiler> {
    let cwd = env::current_dir().unwrap();
    COMPILERS.iter()
        .filter_map(|c| {
            match which_in(c, env::var_os("PATH"), &cwd) {
                Ok(full_path) => match full_path.canonicalize() {
                    Ok(full_path_canon) => Some(Compiler {
                        name: *c,
                        exe: full_path_canon.into_os_string(),
                        env_vars: vec![],
                    }),
                    Err(_) => None,
                },
                Err(_) => None,
            }
        })
        .collect::<Vec<_>>()
}

#[cfg(target_env="msvc")]
fn find_compilers() -> Vec<Compiler> {
    let tool = gcc::Config::new()
        .opt_level(1)
        .host("x86_64-pc-windows-msvc")
        .target("x86_64-pc-windows-msvc")
        .debug(false)
        .get_compiler();
    vec![
        Compiler {
            name: "cl.exe",
            exe: tool.path().as_os_str().to_os_string(),
            env_vars: tool.env().to_vec(),
        },
    ]
}

#[test]
#[cfg(any(unix, target_env="msvc"))]
fn test_sccache_command() {
    match env_logger::init() {
        Ok(_) => {},
        Err(_) => {},
    }
    let tempdir = TempDir::new("sccache_system_test").unwrap();
    let sccache = find_sccache_binary();
    let compilers = find_compilers();
    if compilers.is_empty() {
        warn!("No compilers found, skipping test");
    } else {
        for compiler in compilers {
            run_sccache_command_test(&sccache, compiler, tempdir.path())
        }
    }
}
<commit_msg>Silence a deprecation warning in system tests on Windows<commit_after>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code, unused_imports)]

extern crate gcc;

use client::connect_with_retry;
use env_logger;
use log::LogLevel::Trace;
use serde_json;
use server::ServerInfo;
use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr,OsString};
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path,PathBuf};
use std::process::{
    Command,
    Output,
    Stdio,
};
use tempdir::TempDir;
use test::utils::*;
use which::which_in;

struct Compiler {
    pub name: &'static str,
    pub exe: OsString,
    pub env_vars: Vec<(OsString, OsString)>,
}

// Test GCC + clang on non-OS X platforms.
#[cfg(all(unix, not(target_os="macos")))]
const COMPILERS: &'static [&'static str] = &["gcc", "clang"];

// OS X ships a `gcc` that's just a clang wrapper, so only test clang there.
#[cfg(target_os="macos")]
const COMPILERS: &'static [&'static str] = &["clang"];

//TODO: could test gcc when targeting mingw.

fn do_run<T: AsRef<OsStr>>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> Output {
    let mut cmd = Command::new(exe);
    cmd.args(args)
        .current_dir(cwd)
        .stdout(Stdio::piped())
        .stderr(Stdio::piped());
    for &(ref k, ref v) in env_vars.iter() {
        cmd.env(k, v);
    }
    trace!("do_run: {:?}", cmd);
    cmd.spawn()
        .unwrap_or_else(|e| { panic!("failed to execute child: {}", e) })
        .wait_with_output()
        .unwrap()
}

fn run_stdout<T>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> String
    where T: AsRef<OsStr> + fmt::Debug,
{
    let output = do_run(exe, args, cwd, env_vars);
    assert!(output.status.success(), "Failed to run {:?} {:?}", exe, args);
    String::from_utf8(output.stdout).expect("Couldn't convert stdout to String")
}

fn run<T: AsRef<OsStr>>(exe: &Path, args: &[T], cwd: &Path, env_vars: &[(OsString, OsString)]) -> bool {
    let output = do_run(exe, args, cwd, env_vars);
    if output.status.success() {
        true
    } else {
        let va = args.iter().map(|a| a.as_ref().to_str().unwrap()).collect::<Vec<_>>();
        println!("Process `{:?} {}` failed:", exe, va.join(" "));
        print!("stdout: `");
        io::stdout().write(&output.stdout).unwrap();
        println!("`");
        print!("stderr: `");
        io::stdout().write(&output.stderr).unwrap();
        println!("`");
        false
    }
}

macro_rules! vec_from {
    ( $t:ty, $( $x:expr ),* ) => {
        vec!($( Into::<$t>::into(&$x), )*)
    };
}

fn compile_cmdline<T: AsRef<OsStr>>(compiler: &str, exe: T, input: &str, output: &str) -> Vec<OsString> {
    match compiler {
        "gcc" | "clang" => vec_from!(OsString, exe.as_ref(), "-c", input, "-o", output),
        "cl.exe" => vec_from!(OsString, exe, "-c", input, format!("-Fo{}", output)),
        _ => panic!("Unsupported compiler: {}", compiler),
    }
}

fn get_stats(sccache: &Path, cwd: &Path) -> ServerInfo {
    let output = run_stdout(sccache, &["--show-stats", "--stats-format=json"], cwd, &[]);
    serde_json::from_str(&output).expect("Failed to parse JSON stats")
}

fn run_sccache_command_test(sccache: &Path, compiler: Compiler, tempdir: &Path) {
    let Compiler { name, exe, env_vars } = compiler;
    // Ensure there's no existing sccache server running.
    trace!("stop server");
    do_run(sccache, &["--stop-server"], tempdir, &[]);
    // Create a subdir for the cache.
    let cache = tempdir.join("cache");
    fs::create_dir_all(&cache).unwrap();
    // Start a server.
    trace!("start server");
    // Don't run this with run() because on Windows `wait_with_output`
    // will hang because the internal server process is not detached.
    assert!(Command::new(sccache)
            .arg("--start-server")
            .current_dir(tempdir)
            .env("SCCACHE_DIR", &cache)
            .status()
            .unwrap()
            .success());
    trace!("run_sccache_command_test: {}", name);
    // Compile a source file.
    const INPUT: &'static str = "test.c";
    const INPUT_ERR: &'static str = "test_err.c";
    const OUTPUT: &'static str = "test.o";
    // Copy the source files into the tempdir so we can compile with relative paths, since the commandline winds up in the hash key.
    for f in &[INPUT, INPUT_ERR] {
        let original_source_file = Path::new(file!()).parent().unwrap().join(f);
        let source_file = tempdir.join(f);
        trace!("fs::copy({:?}, {:?})", original_source_file, source_file);
        fs::copy(&original_source_file, &source_file).unwrap();
    }

    let out_file = tempdir.join("test.o");
    trace!("compile");
    assert_eq!(true, run(sccache, &compile_cmdline(name, &exe, INPUT, OUTPUT), tempdir, &env_vars));
    assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
    trace!("request stats");
    let info = get_stats(sccache, tempdir);
    assert_eq!(1, info.stats.compile_requests);
    assert_eq!(1, info.stats.requests_executed);
    assert_eq!(0, info.stats.cache_hits);
    assert_eq!(1, info.stats.cache_misses);
    trace!("compile");
    fs::remove_file(&out_file).unwrap();
    assert_eq!(true, run(sccache, &compile_cmdline(name, &exe, INPUT, OUTPUT), tempdir, &env_vars));
    assert_eq!(true, fs::metadata(&out_file).and_then(|m| Ok(m.len() > 0)).unwrap());
    trace!("request stats");
    let info = get_stats(sccache, tempdir);
    assert_eq!(2, info.stats.compile_requests);
    assert_eq!(2, info.stats.requests_executed);
    assert_eq!(1, info.stats.cache_hits);
    assert_eq!(1, info.stats.cache_misses);
    if name == "cl.exe" {
        // Check that -deps works.
        trace!("compile with -deps");
        let mut args = compile_cmdline(name, &exe, INPUT, OUTPUT);
        args.push("-depstest.d".into());
        assert_eq!(true, run(sccache, &args, tempdir, &env_vars));
        // Check the contents
        let mut f = File::open(tempdir.join("test.d")).expect("Failed to open dep file");
        let mut buf = String::new();
        // read_to_string should be safe because we're supplying all the filenames here,
        // and there are no absolute paths.
        f.read_to_string(&mut buf).expect("Failed to read dep file");
        let lines: Vec<_> = buf.lines().map(|l| l.trim_right()).collect();
        let expected = format!("{output}: {input}\n{input}:\n", output=OUTPUT, input=INPUT);
        let expected_lines: Vec<_> = expected.lines().collect();
        assert_eq!(lines, expected_lines);
    }
    if name == "gcc" {
        trace!("test -MP with -Werror");
        let mut args = compile_cmdline(name, &exe, INPUT_ERR, OUTPUT);
        args.extend(vec_from!(OsString, "-MD", "-MP", "-MF", "foo.pp", "-Werror"));
        let output = do_run(sccache, &args, tempdir, &env_vars);
        assert!(!output.status.success());
        // This should fail, but the error should be from the #error!
        let stderr = String::from_utf8(output.stderr).expect("Couldn't convert stderr to String");
        assert!(stderr.find("to generate dependencies you must specify either -M or -MM").is_none(), "Should not have complained about commandline arguments");
    }
    trace!("stop server");
    assert_eq!(true, run(sccache, &["--stop-server"], tempdir, &[]));
}

#[cfg(unix)]
fn find_compilers() -> Vec<Compiler> {
    let cwd = env::current_dir().unwrap();
    COMPILERS.iter()
        .filter_map(|c| {
            match which_in(c, env::var_os("PATH"), &cwd) {
                Ok(full_path) => match full_path.canonicalize() {
                    Ok(full_path_canon) => Some(Compiler {
                        name: *c,
                        exe: full_path_canon.into_os_string(),
                        env_vars: vec![],
                    }),
                    Err(_) => None,
                },
                Err(_) => None,
            }
        })
        .collect::<Vec<_>>()
}

#[cfg(target_env="msvc")]
fn find_compilers() -> Vec<Compiler> {
    let tool = gcc::Build::new()
        .opt_level(1)
        .host("x86_64-pc-windows-msvc")
        .target("x86_64-pc-windows-msvc")
        .debug(false)
        .get_compiler();
    vec![
        Compiler {
            name: "cl.exe",
            exe: tool.path().as_os_str().to_os_string(),
            env_vars: tool.env().to_vec(),
        },
    ]
}

#[test]
#[cfg(any(unix, target_env="msvc"))]
fn test_sccache_command() {
    match env_logger::init() {
        Ok(_) => {},
        Err(_) => {},
    }
    let tempdir = TempDir::new("sccache_system_test").unwrap();
    let sccache = find_sccache_binary();
    let compilers = find_compilers();
    if compilers.is_empty() {
        warn!("No compilers found, skipping test");
    } else {
        for compiler in compilers {
            run_sccache_command_test(&sccache, compiler, tempdir.path())
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_uname"]

// This file is part of the uutils coreutils package.
//
// (c) Joao Oliveira <joaoxsouls@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

// last synced with: uname (GNU coreutils) 8.21

#[macro_use]
extern crate uucore;
use uucore::utsname::Uname;

static SYNTAX: &'static str = "[OPTION]...";
static SUMMARY: &'static str = "Print certain system information.  With no OPTION, same as -s.";

#[cfg(target_os = "linux")]
static HOST_OS: &'static str = "GNU/Linux";
#[cfg(target_os = "windows")]
static HOST_OS: &'static str = "Windows NT";
#[cfg(target_os = "freebsd")]
static HOST_OS: &'static str = "FreeBSD";
#[cfg(target_os = "openbsd")]
static HOST_OS: &'static str = "OpenBSD";
#[cfg(target_os = "macos")]
static HOST_OS: &'static str = "Darwin";
#[cfg(target_os = "fuchsia")]
static HOST_OS: &'static str = "Fuchsia";

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = new_coreopts!(SYNTAX, SUMMARY, "");

    opts.optflag("a",
                 "all",
                 "Behave as though all of the options -mnrsv were specified.");
    opts.optflag("s", "sysname", "print the operating system name.");
    opts.optflag("n", "nodename", "print the nodename (the nodename may be a name that the system is known by to a communications network).");
    opts.optflag("r", "kernel-release", "print the operating system release.");
    opts.optflag("v", "kernel-version", "print the operating system version.");
    opts.optflag("m", "machine", "print the machine hardware name.");

    // FIXME: Unimplemented
    // opts.optflag("p", "processor", "print the machine processor architecture name.");
    // opts.optflag("i", "hardware-platform", "print the hardware platform.");

    opts.optflag("o", "operating-system", "print the operating system");
    let argc = args.len();
    let matches = opts.parse(args);
    let uname = Uname::new();
    let mut output = String::new();
    if matches.opt_present("sysname") || matches.opt_present("all") || argc == 1 {
        output.push_str(uname.sysname().as_ref());
        output.push_str(" ");
    }

    if matches.opt_present("nodename") || matches.opt_present("all") {
        output.push_str(uname.nodename().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("kernel-release") || matches.opt_present("all") {
        output.push_str(uname.release().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("kernel-version") || matches.opt_present("all") {
        output.push_str(uname.version().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("machine") || matches.opt_present("all") {
        output.push_str(uname.machine().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("operating-system") || matches.opt_present("all") {
        output.push_str(HOST_OS);
        output.push_str(" ");
    }
    println!("{}", output.trim());

    0
}
<commit_msg>uname: change sysname flag to kernel-name<commit_after>#![crate_name = "uu_uname"]

// This file is part of the uutils coreutils package.
//
// (c) Joao Oliveira <joaoxsouls@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//

// last synced with: uname (GNU coreutils) 8.21

#[macro_use]
extern crate uucore;
use uucore::utsname::Uname;

static SYNTAX: &'static str = "[OPTION]...";
static SUMMARY: &'static str = "Print certain system information.  With no OPTION, same as -s.";

#[cfg(target_os = "linux")]
static HOST_OS: &'static str = "GNU/Linux";
#[cfg(target_os = "windows")]
static HOST_OS: &'static str = "Windows NT";
#[cfg(target_os = "freebsd")]
static HOST_OS: &'static str = "FreeBSD";
#[cfg(target_os = "openbsd")]
static HOST_OS: &'static str = "OpenBSD";
#[cfg(target_os = "macos")]
static HOST_OS: &'static str = "Darwin";
#[cfg(target_os = "fuchsia")]
static HOST_OS: &'static str = "Fuchsia";

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = new_coreopts!(SYNTAX, SUMMARY, "");

    opts.optflag("a",
                 "all",
                 "Behave as though all of the options -mnrsv were specified.");
    opts.optflag("s", "kernel-name", "print the operating system name.");
    opts.optflag("n", "nodename", "print the nodename (the nodename may be a name that the system is known by to a communications network).");
    opts.optflag("r", "kernel-release", "print the operating system release.");
    opts.optflag("v", "kernel-version", "print the operating system version.");
    opts.optflag("m", "machine", "print the machine hardware name.");

    // FIXME: Unimplemented
    // opts.optflag("p", "processor", "print the machine processor architecture name.");
    // opts.optflag("i", "hardware-platform", "print the hardware platform.");

    opts.optflag("o", "operating-system", "print the operating system");
    let argc = args.len();
    let matches = opts.parse(args);
    let uname = Uname::new();
    let mut output = String::new();
    if matches.opt_present("sysname") || matches.opt_present("all") || argc == 1 {
        output.push_str(uname.sysname().as_ref());
        output.push_str(" ");
    }

    if matches.opt_present("nodename") || matches.opt_present("all") {
        output.push_str(uname.nodename().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("kernel-release") || matches.opt_present("all") {
        output.push_str(uname.release().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("kernel-version") || matches.opt_present("all") {
        output.push_str(uname.version().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("machine") || matches.opt_present("all") {
        output.push_str(uname.machine().as_ref());
        output.push_str(" ");
    }
    if matches.opt_present("operating-system") || matches.opt_present("all") {
        output.push_str(HOST_OS);
        output.push_str(" ");
    }
    println!("{}", output.trim());

    0
}
<|endoftext|>