<commit_before>use mio_uds::UnixStream;
use mio::Ready;
use libc::{self,c_char,uint32_t,int32_t,pid_t};
use std::io::{Seek,SeekFrom};
use std::fs::File;
use std::ffi::CString;
use std::iter::repeat;
use std::ptr::null_mut;
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd};
use tempfile::tempfile;
use serde_json;
use nix;
use nix::unistd::*;

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::state::ConfigState;
use sozu_command::scm_socket::{Listeners,ScmSocket};
use sozu_command::messages::{OrderMessage,OrderMessageAnswer};
use sozu::network::proxy::Server;
use sozu::network::metrics;

use util;
use logging;
use command::Worker;

pub fn start_workers(executable_path: String, config: &Config) -> nix::Result<Vec<Worker>> {
  let state = ConfigState::new();
  let mut workers = Vec::new();
  for index in 0..config.worker_count {
    let listeners = Some(Listeners {
      http: Vec::new(),
      tls:  Vec::new(),
      tcp:  Vec::new(),
    });
    match start_worker_process(&index.to_string(), config, executable_path.clone(), &state, listeners) {
      Ok((pid, command, scm)) => {
        let w =  Worker::new(index as u32, pid, command, scm, config);
        workers.push(w);
      },
      Err(e) => return Err(e)
    };
  }
  Ok(workers)
}

pub fn start_worker(id: u32, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<Worker> {
  match start_worker_process(&id.to_string(), config, executable_path, state, listeners) {
    Ok((pid, command, scm)) => {
      let w = Worker::new(id, pid, command, scm, config);
      Ok(w)
    },
    Err(e) => Err(e)
  }
}

pub fn begin_worker_process(fd: i32, scm: i32, configuration_state_fd: i32, id: i32,
  command_buffer_size: usize, max_command_buffer_size: usize) {
  let mut command: Channel<OrderMessageAnswer,Config> = Channel::new(
    unsafe { UnixStream::from_raw_fd(fd) },
    command_buffer_size,
    max_command_buffer_size
  );

  command.set_nonblocking(false);

  let configuration_state_file = unsafe { File::from_raw_fd(configuration_state_fd) };
  let config_state: ConfigState = serde_json::from_reader(configuration_state_file)
    .expect("could not parse configuration state data");

  let proxy_config = command.read_message().expect("worker could not read configuration from socket");
  //println!("got message: {:?}", proxy_config);

  let worker_id = format!("{}-{:02}", "WRK", id);
  logging::setup(worker_id.clone(), &proxy_config.log_level,
    &proxy_config.log_target, proxy_config.log_access_target.as_ref().map(|s| s.as_str()));
  info!("worker {} starting...", id);

  command.set_nonblocking(true);
  let mut command: Channel<OrderMessageAnswer,OrderMessage> = command.into();
  command.readiness.insert(Ready::readable());

  if let Some(ref metrics) = proxy_config.metrics.as_ref() {
    metrics::setup(&metrics.address, worker_id, metrics.tagged_metrics, metrics.prefix.clone());
  }

  let mut server = Server::new_from_config(command, ScmSocket::new(scm), proxy_config, config_state);

  info!("starting event loop");
  server.run();
  info!("ending event loop");
}

pub fn start_worker_process(id: &str, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<(pid_t, Channel<OrderMessage,OrderMessageAnswer>, ScmSocket)> {
  trace!("parent({})", unsafe { libc::getpid() });

  let mut state_file = tempfile().expect("could not create temporary file for configuration state");
  util::disable_close_on_exec(state_file.as_raw_fd());

  serde_json::to_writer(&mut state_file, state).expect("could not write upgrade data to temporary file");
  state_file.seek(SeekFrom::Start(0)).expect("could not seek to beginning of file");

  let (server, client) = UnixStream::pair().unwrap();
  let (scm_server_fd, scm_client) = UnixStream::pair().unwrap();

  let scm_server = ScmSocket::new(scm_server_fd.into_raw_fd());

  util::disable_close_on_exec(client.as_raw_fd());
  util::disable_close_on_exec(scm_client.as_raw_fd());

  let mut command: Channel<Config,OrderMessageAnswer> = Channel::new(
    server,
    config.command_buffer_size,
    config.max_command_buffer_size
  );
  command.set_nonblocking(false);

  info!("{} launching worker", id);
  debug!("executable path is {}", executable_path);
  match fork() {
    Ok(ForkResult::Parent{ child }) => {
      info!("{} worker launched: {}", id, child);
      command.write_message(config);
      command.set_nonblocking(true);

      if let Some(l) = listeners {
        info!("sending listeners to new worker: {:?}", l);
        let res = scm_server.send_listeners(l);
        info!("sent listeners from master: {:?}", res);
      };
      util::disable_close_on_exec(scm_server.fd);

      let command: Channel<OrderMessage,OrderMessageAnswer> = command.into();
      Ok((child.into(), command, scm_server))
    },
    Ok(ForkResult::Child) => {
      trace!("child({}):\twill spawn a child", unsafe { libc::getpid() });
      Command::new(executable_path)
        .arg("worker")
        .arg("--id")
        .arg(id)
        .arg("--fd")
        .arg(client.as_raw_fd().to_string())
        .arg("--scm")
        .arg(scm_client.as_raw_fd().to_string())
        .arg("--configuration-state-fd")
        .arg(state_file.as_raw_fd().to_string())
        .arg("--command-buffer-size")
        .arg(config.command_buffer_size.to_string())
        .arg("--max-command-buffer-size")
        .arg(config.max_command_buffer_size.to_string())
        .exec();

      unreachable!();
    },
    Err(e) => {
      error!("Error during fork(): {}", e);
      Err(e)
    }
  }
}

#[cfg(target_os = "linux")]
pub unsafe fn get_executable_path() -> String {
  use std::fs;

  let path         = fs::read_link("/proc/self/exe").expect("/proc/self/exe doesn't exist");
  let mut path_str = path.into_os_string().into_string().expect("Failed to convert PathBuf to String");

  if path_str.ends_with(" (deleted)") {
    // The kernel appends " (deleted)" to the symlink when the original executable has been replaced
    let len = path_str.len();
    path_str.truncate(len - 10)
  }

  path_str
}

#[cfg(target_os = "macos")]
extern {
  pub fn _NSGetExecutablePath(buf: *mut c_char, size: *mut uint32_t) -> int32_t;
}

#[cfg(target_os = "macos")]
pub unsafe fn get_executable_path() -> String {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let mut size:uint32_t = capacity as u32;
  if _NSGetExecutablePath(ptr, &mut size) == 0 {

    let mut temp2:Vec<u8> = Vec::with_capacity(capacity);
    temp2.extend(repeat(0).take(capacity));
    let pathbuf2 = CString::from_vec_unchecked(temp2);
    let ptr2 = pathbuf2.into_raw();

    if libc::realpath(ptr, ptr2) != null_mut() {
      let path = CString::from_raw(ptr2);
      path.to_str().expect("failed to convert CString to String").to_string()
    } else {
      panic!();
    }
  } else {
    panic!("buffer too small");
  }
}
<commit_msg>remove some warnings<commit_after>use mio_uds::UnixStream;
use mio::Ready;
use libc::pid_t;
use std::io::{Seek,SeekFrom};
use std::fs::File;
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd};
use tempfile::tempfile;
use serde_json;
use nix;
use nix::unistd::*;

#[cfg(target_os = "macos")]
use std::ffi::CString;
#[cfg(target_os = "macos")]
use libc::{self,c_char,uint32_t,int32_t};
#[cfg(target_os = "macos")]
use std::iter::repeat;
#[cfg(target_os = "macos")]
use std::ptr::null_mut;

use sozu_command::config::Config;
use sozu_command::channel::Channel;
use sozu_command::state::ConfigState;
use sozu_command::scm_socket::{Listeners,ScmSocket};
use sozu_command::messages::{OrderMessage,OrderMessageAnswer};
use sozu::network::proxy::Server;
use sozu::network::metrics;

use util;
use logging;
use command::Worker;

pub fn start_workers(executable_path: String, config: &Config) -> nix::Result<Vec<Worker>> {
  let state = ConfigState::new();
  let mut workers = Vec::new();
  for index in 0..config.worker_count {
    let listeners = Some(Listeners {
      http: Vec::new(),
      tls:  Vec::new(),
      tcp:  Vec::new(),
    });
    match start_worker_process(&index.to_string(), config, executable_path.clone(), &state, listeners) {
      Ok((pid, command, scm)) => {
        let w =  Worker::new(index as u32, pid, command, scm, config);
        workers.push(w);
      },
      Err(e) => return Err(e)
    };
  }
  Ok(workers)
}

pub fn start_worker(id: u32, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<Worker> {
  match start_worker_process(&id.to_string(), config, executable_path, state, listeners) {
    Ok((pid, command, scm)) => {
      let w = Worker::new(id, pid, command, scm, config);
      Ok(w)
    },
    Err(e) => Err(e)
  }
}

pub fn begin_worker_process(fd: i32, scm: i32, configuration_state_fd: i32, id: i32,
  command_buffer_size: usize, max_command_buffer_size: usize) {
  let mut command: Channel<OrderMessageAnswer,Config> = Channel::new(
    unsafe { UnixStream::from_raw_fd(fd) },
    command_buffer_size,
    max_command_buffer_size
  );

  command.set_nonblocking(false);

  let configuration_state_file = unsafe { File::from_raw_fd(configuration_state_fd) };
  let config_state: ConfigState = serde_json::from_reader(configuration_state_file)
    .expect("could not parse configuration state data");

  let proxy_config = command.read_message().expect("worker could not read configuration from socket");
  //println!("got message: {:?}", proxy_config);

  let worker_id = format!("{}-{:02}", "WRK", id);
  logging::setup(worker_id.clone(), &proxy_config.log_level,
    &proxy_config.log_target, proxy_config.log_access_target.as_ref().map(|s| s.as_str()));
  info!("worker {} starting...", id);

  command.set_nonblocking(true);
  let mut command: Channel<OrderMessageAnswer,OrderMessage> = command.into();
  command.readiness.insert(Ready::readable());

  if let Some(ref metrics) = proxy_config.metrics.as_ref() {
    metrics::setup(&metrics.address, worker_id, metrics.tagged_metrics, metrics.prefix.clone());
  }

  let mut server = Server::new_from_config(command, ScmSocket::new(scm), proxy_config, config_state);

  info!("starting event loop");
  server.run();
  info!("ending event loop");
}

pub fn start_worker_process(id: &str, config: &Config, executable_path: String, state: &ConfigState, listeners: Option<Listeners>) -> nix::Result<(pid_t, Channel<OrderMessage,OrderMessageAnswer>, ScmSocket)> {
  trace!("parent({})", unsafe { libc::getpid() });

  let mut state_file = tempfile().expect("could not create temporary file for configuration state");
  util::disable_close_on_exec(state_file.as_raw_fd());

  serde_json::to_writer(&mut state_file, state).expect("could not write upgrade data to temporary file");
  state_file.seek(SeekFrom::Start(0)).expect("could not seek to beginning of file");

  let (server, client) = UnixStream::pair().unwrap();
  let (scm_server_fd, scm_client) = UnixStream::pair().unwrap();

  let scm_server = ScmSocket::new(scm_server_fd.into_raw_fd());

  util::disable_close_on_exec(client.as_raw_fd());
  util::disable_close_on_exec(scm_client.as_raw_fd());

  let mut command: Channel<Config,OrderMessageAnswer> = Channel::new(
    server,
    config.command_buffer_size,
    config.max_command_buffer_size
  );
  command.set_nonblocking(false);

  info!("{} launching worker", id);
  debug!("executable path is {}", executable_path);
  match fork() {
    Ok(ForkResult::Parent{ child }) => {
      info!("{} worker launched: {}", id, child);
      command.write_message(config);
      command.set_nonblocking(true);

      if let Some(l) = listeners {
        info!("sending listeners to new worker: {:?}", l);
        let res = scm_server.send_listeners(l);
        info!("sent listeners from master: {:?}", res);
      };
      util::disable_close_on_exec(scm_server.fd);

      let command: Channel<OrderMessage,OrderMessageAnswer> = command.into();
      Ok((child.into(), command, scm_server))
    },
    Ok(ForkResult::Child) => {
      trace!("child({}):\twill spawn a child", unsafe { libc::getpid() });
      Command::new(executable_path)
        .arg("worker")
        .arg("--id")
        .arg(id)
        .arg("--fd")
        .arg(client.as_raw_fd().to_string())
        .arg("--scm")
        .arg(scm_client.as_raw_fd().to_string())
        .arg("--configuration-state-fd")
        .arg(state_file.as_raw_fd().to_string())
        .arg("--command-buffer-size")
        .arg(config.command_buffer_size.to_string())
        .arg("--max-command-buffer-size")
        .arg(config.max_command_buffer_size.to_string())
        .exec();

      unreachable!();
    },
    Err(e) => {
      error!("Error during fork(): {}", e);
      Err(e)
    }
  }
}

#[cfg(target_os = "linux")]
pub unsafe fn get_executable_path() -> String {
  use std::fs;

  let path         = fs::read_link("/proc/self/exe").expect("/proc/self/exe doesn't exist");
  let mut path_str = path.into_os_string().into_string().expect("Failed to convert PathBuf to String");

  if path_str.ends_with(" (deleted)") {
    // The kernel appends " (deleted)" to the symlink when the original executable has been replaced
    let len = path_str.len();
    path_str.truncate(len - 10)
  }

  path_str
}

#[cfg(target_os = "macos")]
extern {
  pub fn _NSGetExecutablePath(buf: *mut c_char, size: *mut uint32_t) -> int32_t;
}

#[cfg(target_os = "macos")]
pub unsafe fn get_executable_path() -> String {
  let capacity = 2000;
  let mut temp:Vec<u8> = Vec::with_capacity(capacity);
  temp.extend(repeat(0).take(capacity));
  let pathbuf = CString::from_vec_unchecked(temp);
  let ptr = pathbuf.into_raw();

  let mut size:uint32_t = capacity as u32;
  if _NSGetExecutablePath(ptr, &mut size) == 0 {

    let mut temp2:Vec<u8> = Vec::with_capacity(capacity);
    temp2.extend(repeat(0).take(capacity));
    let pathbuf2 = CString::from_vec_unchecked(temp2);
    let ptr2 = pathbuf2.into_raw();

    if libc::realpath(ptr, ptr2) != null_mut() {
      let path = CString::from_raw(ptr2);
      path.to_str().expect("failed to convert CString to String").to_string()
    } else {
      panic!();
    }
  } else {
    panic!("buffer too small");
  }
}
<|endoftext|>


<commit_before>use encoding::label::encoding_from_whatwg_label;
use encoding::DecoderTrap;
use libc;
use std;
use std::cell::RefCell;
use std::ptr;
use std::rc::Rc;
use std::str;

use attributes::Attribute;
use css;
use handle::{self, RsvgHandle};
use load::rsvg_load_new_node;
use node::{node_new, Node, NodeType};
use property_bag::PropertyBag;
use structure::NodeSvg;
use text::NodeChars;
use tree::{RsvgTree, Tree};
use util::utf8_cstr;

/// A trait for processing a certain kind of XML subtree
///
/// In the "normal" state of processing, an `XmlHandler` may create an RsvgNode
/// for each SVG element it finds, and create NodeChars inside those nodes when it
/// encounters character data.
///
/// There may be other, special contexts for different subtrees, for example,
/// for the `<style>` element.
trait XmlHandler {
    /// Called when the XML parser sees the beginning of an element
    fn start_element(
        &self,
        previous_handler: Option<&XmlHandler>,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler>;

    /// Called when the XML parser sees the end of an element.
    fn end_element(&self, handle: *mut RsvgHandle, name: &str) -> Option<Rc<Node>>;

    /// Called when the XML parser sees character data or CDATA
    fn characters(&self, text: &str);

    fn get_node(&self) -> Option<Rc<Node>> {
        None
    }
}

struct NodeCreationContext {
    node: Option<Rc<Node>>,
}

impl XmlHandler for NodeCreationContext {
    fn start_element(
        &self,
        _previous_handler: Option<&XmlHandler>,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler> {
        match name {
            "include" => {
                let ctx = XIncludeContext::empty();
                ctx.start_element(Some(self), parent, handle, name, pbag)
            }

            "style" => {
                let ctx = StyleContext::empty();
                ctx.start_element(Some(self), parent, handle, name, pbag)
            }

            _ => {
                let node = self.create_node(parent, handle, name, pbag);

                Box::new(NodeCreationContext { node: Some(node) })
            }
        }
    }

    fn end_element(&self, handle: *mut RsvgHandle, _name: &str) -> Option<Rc<Node>> {
        let node = self.node.as_ref().unwrap().clone();

        // The "svg" node is special; it parses its style attributes
        // here, not during element creation.
        if node.get_type() == NodeType::Svg {
            node.with_impl(|svg: &NodeSvg| {
                svg.set_delayed_style(&node, handle);
            });
        }

        Some(node)
    }

    fn characters(&self, text: &str) {
        let node = self.node.as_ref().unwrap();

        if text.len() == 0 {
            return;
        }

        if node.accept_chars() {
            let chars_node = if let Some(child) = node.find_last_chars_child() {
                child
            } else {
                let child = node_new(
                    NodeType::Chars,
                    Some(&node),
                    "rsvg-chars",
                    None,
                    None,
                    Box::new(NodeChars::new()),
                );
                node.add_child(&child);
                child
            };

            chars_node.with_impl(|chars: &NodeChars| {
                chars.append(text);
            });
        }
    }

    fn get_node(&self) -> Option<Rc<Node>> {
        Some(self.node.as_ref().unwrap().clone())
    }
}

impl NodeCreationContext {
    fn empty() -> NodeCreationContext {
        NodeCreationContext { node: None }
    }

    fn create_node(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Rc<Node> {
        let mut defs = handle::get_defs(handle);

        let new_node = rsvg_load_new_node(name, parent, pbag, &mut defs);

        if let Some(parent) = parent {
            parent.add_child(&new_node);
        }

        new_node.set_atts(&new_node, handle, pbag);

        // The "svg" node is special; it will parse its style attributes
        // until the end, in standard_element_end().
        if new_node.get_type() != NodeType::Svg {
            new_node.set_style(handle, pbag);
        }

        new_node.set_overridden_properties();

        new_node
    }
}

/// Handles the `<style>` element by parsing its character contents as CSS
struct StyleContext {
    is_text_css: bool,
    text: RefCell<String>,
}

impl XmlHandler for StyleContext {
    fn start_element(
        &self,
        _previous_handler: Option<&XmlHandler>,
        _parent: Option<&Rc<Node>>,
        _handle: *mut RsvgHandle,
        _name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler> {
        // FIXME: See these:
        //
        // https://www.w3.org/TR/SVG/styling.html#StyleElementTypeAttribute
        // https://www.w3.org/TR/SVG/styling.html#ContentStyleTypeAttribute
        //
        // If the "type" attribute is not present, we should fallback to the
        // "contentStyleType" attribute of the svg element, which in turn
        // defaults to "text/css".
        //
        // See where is_text_css is used to see where we parse the contents
        // of the style element.

        let mut is_text_css = true;

        for (_key, attr, value) in pbag.iter() {
            if attr == Attribute::Type {
                is_text_css = value == "text/css";
            }
        }

        Box::new(StyleContext {
            is_text_css,
            text: RefCell::new(String::new()),
        })
    }

    fn end_element(&self, handle: *mut RsvgHandle, _name: &str) -> Option<Rc<Node>> {
        if self.is_text_css {
            let text = self.text.borrow();
            css::parse_into_handle(handle, &text);
        }

        None
    }

    fn characters(&self, text: &str) {
        self.text.borrow_mut().push_str(text);
    }
}

impl StyleContext {
    fn empty() -> StyleContext {
        StyleContext {
            is_text_css: false,
            text: RefCell::new(String::new()),
        }
    }
}

struct XIncludeContext {
    needs_fallback: bool,
}

impl XmlHandler for XIncludeContext {
    fn start_element(
        &self,
        _previous_handler: Option<&XmlHandler>,
        _parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        _name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler> {
        let mut href = None;
        let mut parse = None;
        let mut encoding = None;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::Href => href = Some(value),
                Attribute::Parse => parse = Some(value),
                Attribute::Encoding => encoding = Some(value),
                _ => (),
            }
        }

        self.acquire(handle, href, parse, encoding);

        unimplemented!("finish start_xinclude() here");

        Box::new(XIncludeContext::empty())
    }

    fn end_element(&self, handle: *mut RsvgHandle, _name: &str) -> Option<Rc<Node>> {
        unimplemented!();
    }

    fn characters(&self, text: &str) {
        unimplemented!();
    }
}

impl XIncludeContext {
    fn empty() -> XIncludeContext {
        XIncludeContext {
            needs_fallback: true,
        }
    }

    fn acquire(
        &self,
        handle: *mut RsvgHandle,
        href: Option<&str>,
        parse: Option<&str>,
        encoding: Option<&str>,
    ) {
        if let Some(href) = href {
            if parse == Some("text") {
                self.acquire_text(handle, href, encoding);
            } else {
                unimplemented!("finish the xml case here");
            }
        }
    }

    fn acquire_text(&self, handle: *mut RsvgHandle, href: &str, encoding: Option<&str>) {
        let binary = match handle::acquire_data(handle, href) {
            Ok(b) => b,
            Err(e) => {
                rsvg_log!("could not acquire \"{}\": {}", href, e);
                return;
            }
        };

        let encoding = encoding.unwrap_or("utf-8");

        let encoder = match encoding_from_whatwg_label(encoding) {
            Some(enc) => enc,
            None => {
                rsvg_log!("unknown encoding \"{}\" for \"{}\"", encoding, href);
                return;
            }
        };

        let utf8_data = match encoder.decode(&binary.data, DecoderTrap::Strict) {
            Ok(data) => data,

            Err(e) => {
                rsvg_log!(
                    "could not convert contents of \"{}\" from character encoding \"{}\": {}",
                    href,
                    encoding,
                    e
                );
                return;
            }
        };

        unimplemented!("rsvg_xml_state_characters(utf8_data)");
    }
}

/// A concrete parsing context for a surrounding `element_name` and its XML event handlers
struct Context {
    element_name: String,
    handler: Box<XmlHandler>,
}

// A *const RsvgXmlState is just the type that we export to C
pub enum RsvgXmlState {}

/// Holds the state used for XML processing
///
/// These methods are called when an XML event is parsed out of the XML stream: `start_element`,
/// `end_element`, `characters`.
///
/// When an element starts, we push a corresponding `Context` into the `context_stack`.  Within
/// that context, all XML events will be forwarded to it, and processed in one of the `XmlHandler`
/// trait objects. Normally the context refers to a `NodeCreationContext` implementation which is
/// what creates normal graphical elements.
///
/// When we get to a `<style>` element, we push a `StyleContext`, which processes its contents
/// specially.
struct XmlState {
    tree: Option<Box<Tree>>,

    context_stack: Vec<Context>,
}

impl XmlState {
    fn new() -> XmlState {
        XmlState {
            tree: None,
            context_stack: Vec::new(),
        }
    }

    pub fn set_root(&mut self, root: &Rc<Node>) {
        if self.tree.is_some() {
            panic!("The tree root has already been set");
        }

        self.tree = Some(Box::new(Tree::new(root)));
    }

    pub fn steal_tree(&mut self) -> Option<Box<Tree>> {
        self.tree.take()
    }

    pub fn start_element(&mut self, handle: *mut RsvgHandle, name: &str, pbag: &PropertyBag) {
        let next_context = if let Some(top) = self.context_stack.last() {
            top.handler.start_element(
                Some(&*top.handler),
                top.handler.get_node().as_ref(),
                handle,
                name,
                pbag,
            )
        } else {
            let default_context = NodeCreationContext::empty();

            default_context.start_element(None, None, handle, name, pbag)
        };

        let context = Context {
            element_name: name.to_string(),
            handler: next_context,
        };

        self.context_stack.push(context);
    }

    pub fn end_element(&mut self, handle: *mut RsvgHandle, name: &str) {
        if let Some(top) = self.context_stack.pop() {
            assert!(name == top.element_name);

            if let Some(node) = top.handler.end_element(handle, name) {
                if self.context_stack.is_empty() {
                    self.set_root(&node);
                }
            }
        } else {
            panic!("end_element: XML handler stack is empty!?");
        }
    }

    pub fn characters(&mut self, text: &str) {
        if let Some(top) = self.context_stack.last() {
            top.handler.characters(text);
        } else {
            panic!("characters: XML handler stack is empty!?");
        }
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_new() -> *mut RsvgXmlState {
    Box::into_raw(Box::new(XmlState::new())) as *mut RsvgXmlState
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_free(xml: *mut RsvgXmlState) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };
    unsafe {
        Box::from_raw(xml);
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_steal_tree(xml: *mut RsvgXmlState) -> *mut RsvgTree {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    if let Some(tree) = xml.steal_tree() {
        Box::into_raw(tree) as *mut RsvgTree
    } else {
        ptr::null_mut()
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_start_element(
    xml: *mut RsvgXmlState,
    handle: *mut RsvgHandle,
    name: *const libc::c_char,
    pbag: *const PropertyBag,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!name.is_null());
    let name = unsafe { utf8_cstr(name) };

    assert!(!pbag.is_null());
    let pbag = unsafe { &*pbag };

    xml.start_element(handle, name, pbag);
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_end_element(
    xml: *mut RsvgXmlState,
    handle: *mut RsvgHandle,
    name: *const libc::c_char,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!name.is_null());
    let name = unsafe { utf8_cstr(name) };

    xml.end_element(handle, name);
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_characters(
    xml: *mut RsvgXmlState,
    unterminated_text: *const libc::c_char,
    len: usize,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!unterminated_text.is_null());

    // libxml2 already validated the incoming string as UTF-8.  Note that
    // it is *not* nul-terminated; this is why we create a byte slice first.
    let bytes = unsafe { std::slice::from_raw_parts(unterminated_text as *const u8, len) };
    let utf8 = unsafe { str::from_utf8_unchecked(bytes) };

    xml.characters(utf8);
}
<commit_msg>Don't use dynamic dispatch for the XML handlers; we only have three cases anyway<commit_after>use encoding::label::encoding_from_whatwg_label;
use encoding::DecoderTrap;
use libc;
use std;
use std::cell::RefCell;
use std::mem;
use std::ptr;
use std::rc::Rc;
use std::str;

use attributes::Attribute;
use css;
use handle::{self, RsvgHandle};
use load::rsvg_load_new_node;
use node::{node_new, Node, NodeType};
use property_bag::PropertyBag;
use structure::NodeSvg;
use text::NodeChars;
use tree::{RsvgTree, Tree};
use util::utf8_cstr;

// struct XIncludeContext {
// needs_fallback: bool,
// }
//
// impl XmlHandler for XIncludeContext {
// fn start_element(
// &self,
// _previous_handler: Option<&XmlHandler>,
// _parent: Option<&Rc<Node>>,
// handle: *mut RsvgHandle,
// _name: &str,
// pbag: &PropertyBag,
// ) -> Box<XmlHandler> {
// let mut href = None;
// let mut parse = None;
// let mut encoding = None;
//
// for (_key, attr, value) in pbag.iter() {
// match attr {
// Attribute::Href => href = Some(value),
// Attribute::Parse => parse = Some(value),
// Attribute::Encoding => encoding = Some(value),
// _ => (),
// }
// }
//
// self.acquire(handle, href, parse, encoding);
//
// unimplemented!("finish start_xinclude() here");
//
// Box::new(XIncludeContext::empty())
// }
//
// fn end_element(&self, handle: *mut RsvgHandle, _name: &str) -> Option<Rc<Node>> {
// unimplemented!();
// }
//
// fn characters(&self, text: &str) {
// unimplemented!();
// }
// }
//
// impl XIncludeContext {
// fn empty() -> XIncludeContext {
// XIncludeContext {
// needs_fallback: true,
// }
// }
//
// fn acquire(
// &self,
// handle: *mut RsvgHandle,
// href: Option<&str>,
// parse: Option<&str>,
// encoding: Option<&str>,
// ) {
// if let Some(href) = href {
// if parse == Some("text") {
// self.acquire_text(handle, href, encoding);
// } else {
// unimplemented!("finish the xml case here");
// }
// }
// }
//
// fn acquire_text(&self, handle: *mut RsvgHandle, href: &str, encoding: Option<&str>) {
// let binary = match handle::acquire_data(handle, href) {
// Ok(b) => b,
// Err(e) => {
// rsvg_log!("could not acquire \"{}\": {}", href, e);
// return;
// }
// };
//
// let encoding = encoding.unwrap_or("utf-8");
//
// let encoder = match encoding_from_whatwg_label(encoding) {
// Some(enc) => enc,
// None => {
// rsvg_log!("unknown encoding \"{}\" for \"{}\"", encoding, href);
// return;
// }
// };
//
// let utf8_data = match encoder.decode(&binary.data, DecoderTrap::Strict) {
// Ok(data) => data,
//
// Err(e) => {
// rsvg_log!(
// "could not convert contents of \"{}\" from character encoding \"{}\": {}",
// href,
// encoding,
// e
// );
// return;
// }
// };
//
// unimplemented!("rsvg_xml_state_characters(utf8_data)");
// }
// }
enum ContextKind {
    // Starting state
    Start,

    // Creating nodes for elements under the given parent
    ElementCreation(Rc<Node>),

    // Inside a <style> element
    Style(StyleContext),

    // An element inside a <style> context, to be ignored
    UnsupportedStyleChild,

    // Inside <xi:include>
    XInclude,
}

/// Handles the `<style>` element by parsing its character contents as CSS
struct StyleContext {
    is_text_css: bool,
    text: String,
}

/// A concrete parsing context for a surrounding `element_name` and its XML event handlers
struct Context {
    element_name: String,
    kind: ContextKind,
}

impl Context {
    fn empty() -> Context {
        Context {
            element_name: String::new(),
            kind: ContextKind::Start,
        }
    }
}

// A *const RsvgXmlState is just the type that we export to C
pub enum RsvgXmlState {}

/// Holds the state used for XML processing
///
/// These methods are called when an XML event is parsed out of the XML stream: `start_element`,
/// `end_element`, `characters`.
///
/// When an element starts, we push a corresponding `Context` into the `context_stack`.  Within
/// that context, all XML events will be forwarded to it, and processed in one of the `XmlHandler`
/// trait objects. Normally the context refers to a `NodeCreationContext` implementation which is
/// what creates normal graphical elements.
///
/// When we get to a `<style>` element, we push a `StyleContext`, which processes its contents
/// specially.
struct XmlState {
    tree: Option<Box<Tree>>,
    context: Context,
    context_stack: Vec<Context>,
}

fn style_characters(style_ctx: &mut StyleContext, text: &str) {
    style_ctx.text.push_str(text);
}

impl XmlState {
    fn new() -> XmlState {
        XmlState {
            tree: None,
            context: Context::empty(),
            context_stack: Vec::new(),
        }
    }

    pub fn set_root(&mut self, root: &Rc<Node>) {
        if self.tree.is_some() {
            panic!("The tree root has already been set");
        }

        self.tree = Some(Box::new(Tree::new(root)));
    }

    pub fn steal_tree(&mut self) -> Option<Box<Tree>> {
        self.tree.take()
    }

    fn push_context(&mut self, ctx: Context) {
        let top = mem::replace(&mut self.context, ctx);
        self.context_stack.push(top);
    }

    pub fn start_element(&mut self, handle: *mut RsvgHandle, name: &str, pbag: &PropertyBag) {
        let new_ctx = match self.context.kind {
            ContextKind::Start => self.element_creation_start_element(None, handle, name, pbag),
            ContextKind::ElementCreation(ref parent) => {
                let parent = parent.clone();
                self.element_creation_start_element(Some(&parent), handle, name, pbag)
            }
            ContextKind::Style(_) => self.style_start_element(true, name, pbag),
            ContextKind::UnsupportedStyleChild => self.style_start_element(true, name, pbag),
            ContextKind::XInclude => self.xinclude_start_element(handle, name, pbag),
        };

        self.push_context(new_ctx);
    }

    pub fn end_element(&mut self, handle: *mut RsvgHandle, name: &str) {
        // We can unwrap since start_element() always adds a context to the stack
        let top = self.context_stack.pop().unwrap();

        let is_root = if let ContextKind::Start = top.kind {
            true
        } else {
            false
        };

        let context = mem::replace(&mut self.context, top);

        assert!(context.element_name == name);

        match context.kind {
            ContextKind::Start => panic!("end_element: XML handler stack is empty!?"),
            ContextKind::ElementCreation(node) => {
                self.element_creation_end_element(is_root, node, handle)
            }
            ContextKind::Style(style_ctx) => self.style_end_element(style_ctx, handle),
            ContextKind::UnsupportedStyleChild => (),
            ContextKind::XInclude => self.xinclude_end_element(handle, name),
        }
    }

    pub fn characters(&mut self, text: &str) {
        match self.context.kind {
            ContextKind::Start => panic!("characters: XML handler stack is empty!?"),
            ContextKind::ElementCreation(ref parent) => {
                self.element_creation_characters(parent, text)
            }
            ContextKind::Style(ref mut style_ctx) => style_characters(style_ctx, text),
            ContextKind::UnsupportedStyleChild => (),
            ContextKind::XInclude => self.xinclude_characters(text),
        }
    }

    fn element_creation_start_element(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Context {
        match name {
            "include" => unimplemented!(),
            "style" => self.style_start_element(false, name, pbag),
            _ => {
                let node = self.create_node(parent, handle, name, pbag);

                Context {
                    element_name: name.to_string(),
                    kind: ContextKind::ElementCreation(node),
                }
            }
        }
    }

    fn element_creation_end_element(
        &mut self,
        is_root: bool,
        node: Rc<Node>,
        handle: *mut RsvgHandle,
    ) {
        // The "svg" node is special; it parses its style attributes
        // here, not during element creation.
        if node.get_type() == NodeType::Svg {
            node.with_impl(|svg: &NodeSvg| {
                svg.set_delayed_style(&node, handle);
            });
        }

        if is_root {
            self.set_root(&node);
        }
    }

    fn element_creation_characters(&self, node: &Rc<Node>, text: &str) {
        if text.len() != 0 && node.accept_chars() {
            let chars_node = if let Some(child) = node.find_last_chars_child() {
                child
            } else {
                let child = node_new(
                    NodeType::Chars,
                    Some(node),
                    "rsvg-chars",
                    None,
                    None,
                    Box::new(NodeChars::new()),
                );
                node.add_child(&child);
                child
            };

            chars_node.with_impl(|chars: &NodeChars| {
                chars.append(text);
            });
        }
    }

    fn create_node(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Rc<Node> {
        let mut defs = handle::get_defs(handle);

        let new_node = rsvg_load_new_node(name, parent, pbag, &mut defs);

        if let Some(parent) = parent {
            parent.add_child(&new_node);
        }

        new_node.set_atts(&new_node, handle, pbag);

        // The "svg" node is special; it will parse its style attributes
        // until the end, in standard_element_end().
        if new_node.get_type() != NodeType::Svg {
            new_node.set_style(handle, pbag);
        }

        new_node.set_overridden_properties();

        new_node
    }

    fn style_start_element(&self, inside_style: bool, name: &str, pbag: &PropertyBag) -> Context {
        if inside_style {
            // We are already inside a <style> element, and we don't support
            // elements in there.  Just push a state that we will ignore.

            return Context {
                element_name: name.to_string(),
                kind: ContextKind::UnsupportedStyleChild,
            };
        }

        // FIXME: See these:
        //
        // https://www.w3.org/TR/SVG11/styling.html#StyleElementTypeAttribute
        // https://www.w3.org/TR/SVG11/styling.html#ContentStyleTypeAttribute
        //
        // If the "type" attribute is not present, we should fallback to the
        // "contentStyleType" attribute of the svg element, which in turn
        // defaults to "text/css".
        //
        // See where is_text_css is used to see where we parse the contents
        // of the style element.

        let mut is_text_css = true;

        for (_key, attr, value) in pbag.iter() {
            if attr == Attribute::Type {
                is_text_css = value == "text/css";
            }
        }

        Context {
            element_name: name.to_string(),
            kind: ContextKind::Style(StyleContext {
                is_text_css,
                text: String::new(),
            }),
        }
    }

    fn style_end_element(&mut self, style_ctx: StyleContext, handle: *mut RsvgHandle) {
        if style_ctx.is_text_css {
            css::parse_into_handle(handle, &style_ctx.text);
        }
    }

    fn xinclude_start_element(
        &mut self,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Context {
        unimplemented!();
    }

    fn xinclude_end_element(&mut self, handle: *mut RsvgHandle, name: &str) {
        unimplemented!();
    }

    fn xinclude_characters(&mut self, text: &str) {
        unimplemented!();
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_new() -> *mut RsvgXmlState {
    Box::into_raw(Box::new(XmlState::new())) as *mut RsvgXmlState
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_free(xml: *mut RsvgXmlState) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };
    unsafe {
        Box::from_raw(xml);
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_steal_tree(xml: *mut RsvgXmlState) -> *mut RsvgTree {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    if let Some(tree) = xml.steal_tree() {
        Box::into_raw(tree) as *mut RsvgTree
    } else {
        ptr::null_mut()
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_start_element(
    xml: *mut RsvgXmlState,
    handle: *mut RsvgHandle,
    name: *const libc::c_char,
    pbag: *const PropertyBag,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!name.is_null());
    let name = unsafe { utf8_cstr(name) };

    assert!(!pbag.is_null());
    let pbag = unsafe { &*pbag };

    xml.start_element(handle, name, pbag);
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_end_element(
    xml: *mut RsvgXmlState,
    handle: *mut RsvgHandle,
    name: *const libc::c_char,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!name.is_null());
    let name = unsafe { utf8_cstr(name) };

    xml.end_element(handle, name);
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_characters(
    xml: *mut RsvgXmlState,
    unterminated_text: *const libc::c_char,
    len: usize,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!unterminated_text.is_null());

    // libxml2 already validated the incoming string as UTF-8.  Note that
    // it is *not* nul-terminated; this is why we create a byte slice first.
    let bytes = unsafe { std::slice::from_raw_parts(unterminated_text as *const u8, len) };
    let utf8 = unsafe { str::from_utf8_unchecked(bytes) };

    xml.characters(utf8);
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// 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.

extern crate cmake;

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

static SHADERC_REPO: &'static str = "https://github.com/google/shaderc";
static GLSLANG_REPO: &'static str = "https://github.com/google/glslang";
static SPIRV_TOOLS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Tools";
static SPIRV_HEADERS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Headers";

// Updated on 2017-09-30
static SHADERC_COMMIT: &'static str = "c8ba3e4694ff554f95000ec35e6e55f2ba637fb3";
static GLSLANG_COMMIT: &'static str = "44dd6a00c388ba09f7ac64a3921b4717a89f949c";
static SPIRV_TOOLS_COMMIT: &'static str = "17a843c6b0ac39edce3ca45246b78c8f47c7ebee";
static SPIRV_HEADERS_COMMIT: &'static str = "77240d9e86c6ff135f6de8c7b89a0099a2d90e16";

fn git_clone_or_update(project: &str, url: &str, commit: &str, dir: &PathBuf) {
    if dir.as_path().exists() {
        let status = Command::new("git")
            .arg("pull")
            .current_dir(dir)
            .status()
            .expect("failed to execute git pull");
        if !status.success() {
            panic!("git pull {} failed", project)
        }
    } else {
        let status = Command::new("git")
            .args(&["clone", url, dir.to_str().unwrap()])
            .status()
            .expect("failed to execute git clone");
        if !status.success() {
            panic!("git clone {} failed", project)
        }
    }

    let status = Command::new("git")
        .args(&["checkout", commit])
        .current_dir(dir)
        .status()
        .expect("failed to execute git checkout");
    if !status.success() {
        panic!("git checkout {} failed", commit)
    }
}

fn build_shaderc(shaderc_dir: &PathBuf) -> PathBuf {
        cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            .build()
}

fn build_shaderc_msvc(shaderc_dir: &PathBuf) -> PathBuf {
    cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            // cmake-rs tries to be clever on Windows by injecting several
            // C/C++ flags, which causes problems. So I have to manually
            // define CMAKE_*_FLAGS_* here to suppress that.
            .define("CMAKE_C_FLAGS", " /nologo /EHsc")
            .define("CMAKE_CXX_FLAGS", " /nologo /EHsc")
            .define("CMAKE_C_FLAGS_RELEASE", " /nologo /EHsc")
            .define("CMAKE_CXX_FLAGS_RELEASE", " /nologo /EHsc")
            .build()
}

fn main() {
    if env::var("CARGO_FEATURE_BUILD_NATIVE_SHADERC").is_err() {
        println!("cargo:warning=requested to skip building native C++ shaderc");
        return
    }
    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let target_dir = Path::new(&manifest_dir).join("target");
    let shaderc_dir = Path::new(&target_dir).join("native-shaderc");
    let third_party_dir = Path::new(&shaderc_dir).join("third_party");
    let glslang_dir = Path::new(&third_party_dir).join("glslang");
    let spirv_tools_dir = Path::new(&third_party_dir).join("spirv-tools");
    let external_dir = Path::new(&spirv_tools_dir).join("external");
    let spirv_headers_dir = Path::new(&external_dir).join("spirv-headers");

    git_clone_or_update("shaderc", SHADERC_REPO, SHADERC_COMMIT, &shaderc_dir);
    git_clone_or_update("glslang", GLSLANG_REPO, GLSLANG_COMMIT, &glslang_dir);
    git_clone_or_update("spirv-tools", SPIRV_TOOLS_REPO, SPIRV_TOOLS_COMMIT, &spirv_tools_dir);
    git_clone_or_update("spirv-headers", SPIRV_HEADERS_REPO, SPIRV_HEADERS_COMMIT, &spirv_headers_dir);

    let mut lib_path = if target_env == "msvc" {
        build_shaderc_msvc(&shaderc_dir)
    } else {
        build_shaderc(&shaderc_dir)
    };

    lib_path.push("lib");

    println!("cargo:rustc-link-lib=static=shaderc_combined");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
}
<commit_msg>Use git fetch instead of git pull<commit_after>// Copyright 2017 Google Inc.
//
// 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.

extern crate cmake;

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

static SHADERC_REPO: &'static str = "https://github.com/google/shaderc";
static GLSLANG_REPO: &'static str = "https://github.com/google/glslang";
static SPIRV_TOOLS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Tools";
static SPIRV_HEADERS_REPO: &'static str = "https://github.com/KhronosGroup/SPIRV-Headers";

// Updated on 2017-09-30
static SHADERC_COMMIT: &'static str = "c8ba3e4694ff554f95000ec35e6e55f2ba637fb3";
static GLSLANG_COMMIT: &'static str = "44dd6a00c388ba09f7ac64a3921b4717a89f949c";
static SPIRV_TOOLS_COMMIT: &'static str = "17a843c6b0ac39edce3ca45246b78c8f47c7ebee";
static SPIRV_HEADERS_COMMIT: &'static str = "77240d9e86c6ff135f6de8c7b89a0099a2d90e16";

fn git_clone_or_update(project: &str, url: &str, commit: &str, dir: &PathBuf) {
    if dir.as_path().exists() {
        let status = Command::new("git")
            .arg("fetch")
            .current_dir(dir)
            .status()
            .expect("failed to execute git pull");
        if !status.success() {
            panic!("git pull {} failed", project)
        }
    } else {
        let status = Command::new("git")
            .args(&["clone", url, dir.to_str().unwrap()])
            .status()
            .expect("failed to execute git clone");
        if !status.success() {
            panic!("git clone {} failed", project)
        }
    }

    let status = Command::new("git")
        .args(&["checkout", commit])
        .current_dir(dir)
        .status()
        .expect("failed to execute git checkout");
    if !status.success() {
        panic!("git checkout {} failed", commit)
    }
}

fn build_shaderc(shaderc_dir: &PathBuf) -> PathBuf {
        cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            .build()
}

fn build_shaderc_msvc(shaderc_dir: &PathBuf) -> PathBuf {
    cmake::Config::new(shaderc_dir)
            .profile("Release")
            .define("CMAKE_POSITION_INDEPENDENT_CODE", "ON")
            .define("SPIRV_SKIP_EXECUTABLES", "ON")
            .define("SHADERC_SKIP_TESTS", "ON")
            // cmake-rs tries to be clever on Windows by injecting several
            // C/C++ flags, which causes problems. So I have to manually
            // define CMAKE_*_FLAGS_* here to suppress that.
            .define("CMAKE_C_FLAGS", " /nologo /EHsc")
            .define("CMAKE_CXX_FLAGS", " /nologo /EHsc")
            .define("CMAKE_C_FLAGS_RELEASE", " /nologo /EHsc")
            .define("CMAKE_CXX_FLAGS_RELEASE", " /nologo /EHsc")
            .build()
}

fn main() {
    if env::var("CARGO_FEATURE_BUILD_NATIVE_SHADERC").is_err() {
        println!("cargo:warning=requested to skip building native C++ shaderc");
        return
    }
    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let target_dir = Path::new(&manifest_dir).join("target");
    let shaderc_dir = Path::new(&target_dir).join("native-shaderc");
    let third_party_dir = Path::new(&shaderc_dir).join("third_party");
    let glslang_dir = Path::new(&third_party_dir).join("glslang");
    let spirv_tools_dir = Path::new(&third_party_dir).join("spirv-tools");
    let external_dir = Path::new(&spirv_tools_dir).join("external");
    let spirv_headers_dir = Path::new(&external_dir).join("spirv-headers");

    git_clone_or_update("shaderc", SHADERC_REPO, SHADERC_COMMIT, &shaderc_dir);
    git_clone_or_update("glslang", GLSLANG_REPO, GLSLANG_COMMIT, &glslang_dir);
    git_clone_or_update("spirv-tools", SPIRV_TOOLS_REPO, SPIRV_TOOLS_COMMIT, &spirv_tools_dir);
    git_clone_or_update("spirv-headers", SPIRV_HEADERS_REPO, SPIRV_HEADERS_COMMIT, &spirv_headers_dir);

    let mut lib_path = if target_env == "msvc" {
        build_shaderc_msvc(&shaderc_dir)
    } else {
        build_shaderc(&shaderc_dir)
    };

    lib_path.push("lib");

    println!("cargo:rustc-link-lib=static=shaderc_combined");
    println!("cargo:rustc-link-search=native={}", lib_path.display());
}
<|endoftext|>


<commit_before>extern crate inkwell;

use self::inkwell::{AddressSpace, IntPredicate, FloatPredicate};
use self::inkwell::context::Context;
use self::inkwell::values::{BasicValue, InstructionOpcode::*};

#[test]
fn test_operands() {
    let context = Context::create();
    let module = context.create_module("ivs");
    let builder = context.create_builder();
    let void_type = context.void_type();
    let f32_type = context.f32_type();
    let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
    let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);

    let function = module.add_function("take_f32_ptr", fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");

    builder.position_at_end(&basic_block);

    let arg1 = function.get_first_param().unwrap().into_pointer_value();
    let f32_val = f32_type.const_float(::std::f64::consts::PI);
    let store_instruction = builder.build_store(arg1, f32_val);
    let free_instruction = builder.build_free(arg1);
    let return_instruction = builder.build_return(None);

    assert_eq!(store_instruction.get_opcode(), Store);
    assert_eq!(free_instruction.get_opcode(), Call);
    assert_eq!(return_instruction.get_opcode(), Return);

    assert!(arg1.as_instruction_value().is_none());

    // Test operands
    assert_eq!(store_instruction.get_num_operands(), 2);
    assert_eq!(free_instruction.get_num_operands(), 2);

    let store_operand0 = store_instruction.get_operand(0).unwrap();
    let store_operand1 = store_instruction.get_operand(1).unwrap();

    assert_eq!(store_operand0.left().unwrap(), f32_val); // f32 const
    assert_eq!(store_operand1.left().unwrap(), arg1); // f32* arg1
    assert!(store_instruction.get_operand(2).is_none());
    assert!(store_instruction.get_operand(3).is_none());
    assert!(store_instruction.get_operand(4).is_none());

    let free_operand0 = free_instruction.get_operand(0).unwrap().left().unwrap();
    let free_operand1 = free_instruction.get_operand(1).unwrap().left().unwrap();
    let free_operand0_instruction = free_operand0.as_instruction_value().unwrap();

    assert!(free_operand0.is_pointer_value()); // (implictly casted) i8* arg1
    assert!(free_operand1.is_pointer_value()); // Free function ptr
    assert_eq!(free_operand0_instruction.get_opcode(), BitCast);
    assert_eq!(free_operand0_instruction.get_operand(0).unwrap().left().unwrap(), arg1);
    assert!(free_operand0_instruction.get_operand(1).is_none());
    assert!(free_operand0_instruction.get_operand(2).is_none());
    assert!(free_instruction.get_operand(2).is_none());
    assert!(free_instruction.get_operand(3).is_none());
    assert!(free_instruction.get_operand(4).is_none());

    assert!(module.verify().is_ok());

    assert!(free_instruction.set_operand(0, arg1));

    // Module is no longer valid because free takes an i8* not f32*
    assert!(module.verify().is_err());

    assert!(free_instruction.set_operand(0, free_operand0));

    assert!(module.verify().is_ok());

    // No-op, free only has two (0-1) operands
    assert!(!free_instruction.set_operand(2, free_operand0));

    assert!(module.verify().is_ok());

    assert_eq!(return_instruction.get_num_operands(), 0);
    assert!(return_instruction.get_operand(0).is_none());
    assert!(return_instruction.get_operand(1).is_none());
    assert!(return_instruction.get_operand(2).is_none());

    // Test Uses
    let bitcast_use_value = free_operand0_instruction
        .get_first_use()
        .unwrap()
        .get_used_value()
        .left()
        .unwrap();
    let free_call_param = free_instruction.get_operand(0).unwrap().left().unwrap();

    assert_eq!(bitcast_use_value, free_call_param);

    // These instructions/calls don't return any ir value so they aren't used anywhere
    assert!(store_instruction.get_first_use().is_none());
    assert!(free_instruction.get_first_use().is_none());
    assert!(return_instruction.get_first_use().is_none());

    // arg1 (%0) has two uses:
    //   store float 0x400921FB60000000, float* %0
    //   %1 = bitcast float* %0 to i8*
    let arg1_first_use = arg1.get_first_use().unwrap();
    let arg1_second_use = arg1_first_use.get_next_use().unwrap();

    // However their operands are used
    let store_operand_use0 = store_instruction.get_operand_use(0).unwrap();
    let store_operand_use1 = store_instruction.get_operand_use(1).unwrap();

    assert!(store_operand_use0.get_next_use().is_none());
    assert!(store_operand_use1.get_next_use().is_none());
    assert_eq!(store_operand_use1, arg1_second_use);

    assert_eq!(store_operand_use0.get_user(), store_instruction);
    assert_eq!(store_operand_use1.get_user(), store_instruction);
    assert_eq!(store_operand_use0.get_used_value().left().unwrap(), f32_val);
    assert_eq!(store_operand_use1.get_used_value().left().unwrap(), arg1);

    assert!(store_instruction.get_operand_use(2).is_none());
    assert!(store_instruction.get_operand_use(3).is_none());
    assert!(store_instruction.get_operand_use(4).is_none());
    assert!(store_instruction.get_operand_use(5).is_none());
    assert!(store_instruction.get_operand_use(6).is_none());

    let free_operand_use0 = free_instruction.get_operand_use(0).unwrap();
    let free_operand_use1 = free_instruction.get_operand_use(1).unwrap();

    assert!(free_operand_use0.get_next_use().is_none());
    assert!(free_operand_use1.get_next_use().is_none());
    assert!(free_instruction.get_operand_use(2).is_none());
    assert!(free_instruction.get_operand_use(3).is_none());
    assert!(free_instruction.get_operand_use(4).is_none());
    assert!(free_instruction.get_operand_use(5).is_none());
    assert!(free_instruction.get_operand_use(6).is_none());

    assert!(module.verify().is_ok());
}

#[test]
fn test_basic_block_operand() {
    let context = Context::create();
    let module = context.create_module("ivs");
    let builder = context.create_builder();
    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);
    let function = module.add_function("bb_op", fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");
    let basic_block2 = context.append_basic_block(&function, "exit");

    builder.position_at_end(&basic_block);

    let branch_instruction = builder.build_unconditional_branch(&basic_block2);
    let bb_operand = branch_instruction.get_operand(0).unwrap().right().unwrap();

    assert_eq!(bb_operand, basic_block2);

    let bb_operand_use = branch_instruction.get_operand_use(0).unwrap();

    assert_eq!(bb_operand_use.get_used_value().right().unwrap(), basic_block2);

    builder.position_at_end(&basic_block2);
    builder.build_return(None);

    assert!(module.verify().is_ok());
}

#[test]
fn test_get_next_use() {
    let context = Context::create();
    let module = context.create_module("ivs");
    let builder = context.create_builder();
    let f32_type = context.f32_type();
    let fn_type = f32_type.fn_type(&[f32_type.into()], false);
    let function = module.add_function("take_f32", fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");

    builder.position_at_end(&basic_block);

    let arg1 = function.get_first_param().unwrap().into_float_value();
    let f32_val = f32_type.const_float(::std::f64::consts::PI);
    let add_pi0 = builder.build_float_add(arg1, f32_val, "add_pi");
    let add_pi1 = builder.build_float_add(add_pi0, f32_val, "add_pi");

    builder.build_return(Some(&add_pi1));

    // f32_val constant appears twice, so there are two uses (first, next)
    let first_use = f32_val.get_first_use().unwrap();

    assert_eq!(first_use.get_user(), add_pi1.as_instruction_value().unwrap());
    assert_eq!(first_use.get_next_use().map(|x| x.get_user()), add_pi0.as_instruction_value());
    assert!(arg1.get_first_use().is_some());
    assert!(module.verify().is_ok());
}

#[test]
fn test_instructions() {
    let context = Context::create();
    let module = context.create_module("testing");
    let builder = context.create_builder();

    let void_type = context.void_type();
    let i64_type = context.i64_type();
    let f32_type = context.f32_type();
    let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
    let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false);

    let function = module.add_function("free_f32", fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");

    builder.position_at_end(&basic_block);

    let arg1 = function.get_first_param().unwrap().into_pointer_value();
    let arg2 = function.get_nth_param(1).unwrap().into_float_value();

    assert!(arg1.get_first_use().is_none());
    assert!(arg2.get_first_use().is_none());

    let f32_val = f32_type.const_float(::std::f64::consts::PI);

    let store_instruction = builder.build_store(arg1, f32_val);
    let ptr_val = builder.build_ptr_to_int(arg1, i64_type, "ptr_val");
    let ptr = builder.build_int_to_ptr(ptr_val, f32_ptr_type, "ptr");
    let icmp = builder.build_int_compare(IntPredicate::EQ, ptr_val, ptr_val, "icmp");
    let f32_sum = builder.build_float_add(arg2, f32_val, "f32_sum");
    let fcmp = builder.build_float_compare(FloatPredicate::OEQ, f32_sum, arg2, "fcmp");
    let free_instruction = builder.build_free(arg1);
    let return_instruction = builder.build_return(None);

    assert_eq!(store_instruction.get_opcode(), Store);
    assert_eq!(ptr_val.as_instruction().unwrap().get_opcode(), PtrToInt);
    assert_eq!(ptr.as_instruction().unwrap().get_opcode(), IntToPtr);
    assert_eq!(icmp.as_instruction().unwrap().get_opcode(), ICmp);
    assert_eq!(icmp.as_instruction().unwrap().get_icmp_predicate().unwrap(), IntPredicate::EQ);
    assert_eq!(f32_sum.as_instruction().unwrap().get_opcode(), FAdd);
    assert_eq!(fcmp.as_instruction().unwrap().get_opcode(), FCmp);
    assert_eq!(fcmp.as_instruction().unwrap().get_fcmp_predicate().unwrap(), FloatPredicate::OEQ);
    assert_eq!(free_instruction.get_opcode(), Call);
    assert_eq!(return_instruction.get_opcode(), Return);

    // test instruction cloning
    let instruction_clone = return_instruction.clone();

    assert_eq!(instruction_clone.get_opcode(), return_instruction.get_opcode());
    assert_ne!(instruction_clone, return_instruction);

    // test copying
    let instruction_clone_copy = instruction_clone;

    assert_eq!(instruction_clone, instruction_clone_copy);
}
<commit_msg>add more tests for icmp/fcmp bindings<commit_after>extern crate inkwell;

use self::inkwell::{AddressSpace, IntPredicate, FloatPredicate};
use self::inkwell::context::Context;
use self::inkwell::values::{BasicValue, InstructionOpcode::*};

#[test]
fn test_operands() {
    let context = Context::create();
    let module = context.create_module("ivs");
    let builder = context.create_builder();
    let void_type = context.void_type();
    let f32_type = context.f32_type();
    let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
    let fn_type = void_type.fn_type(&[f32_ptr_type.into()], false);

    let function = module.add_function("take_f32_ptr", fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");

    builder.position_at_end(&basic_block);

    let arg1 = function.get_first_param().unwrap().into_pointer_value();
    let f32_val = f32_type.const_float(::std::f64::consts::PI);
    let store_instruction = builder.build_store(arg1, f32_val);
    let free_instruction = builder.build_free(arg1);
    let return_instruction = builder.build_return(None);

    assert_eq!(store_instruction.get_opcode(), Store);
    assert_eq!(free_instruction.get_opcode(), Call);
    assert_eq!(return_instruction.get_opcode(), Return);

    assert!(arg1.as_instruction_value().is_none());

    // Test operands
    assert_eq!(store_instruction.get_num_operands(), 2);
    assert_eq!(free_instruction.get_num_operands(), 2);

    let store_operand0 = store_instruction.get_operand(0).unwrap();
    let store_operand1 = store_instruction.get_operand(1).unwrap();

    assert_eq!(store_operand0.left().unwrap(), f32_val); // f32 const
    assert_eq!(store_operand1.left().unwrap(), arg1); // f32* arg1
    assert!(store_instruction.get_operand(2).is_none());
    assert!(store_instruction.get_operand(3).is_none());
    assert!(store_instruction.get_operand(4).is_none());

    let free_operand0 = free_instruction.get_operand(0).unwrap().left().unwrap();
    let free_operand1 = free_instruction.get_operand(1).unwrap().left().unwrap();
    let free_operand0_instruction = free_operand0.as_instruction_value().unwrap();

    assert!(free_operand0.is_pointer_value()); // (implictly casted) i8* arg1
    assert!(free_operand1.is_pointer_value()); // Free function ptr
    assert_eq!(free_operand0_instruction.get_opcode(), BitCast);
    assert_eq!(free_operand0_instruction.get_operand(0).unwrap().left().unwrap(), arg1);
    assert!(free_operand0_instruction.get_operand(1).is_none());
    assert!(free_operand0_instruction.get_operand(2).is_none());
    assert!(free_instruction.get_operand(2).is_none());
    assert!(free_instruction.get_operand(3).is_none());
    assert!(free_instruction.get_operand(4).is_none());

    assert!(module.verify().is_ok());

    assert!(free_instruction.set_operand(0, arg1));

    // Module is no longer valid because free takes an i8* not f32*
    assert!(module.verify().is_err());

    assert!(free_instruction.set_operand(0, free_operand0));

    assert!(module.verify().is_ok());

    // No-op, free only has two (0-1) operands
    assert!(!free_instruction.set_operand(2, free_operand0));

    assert!(module.verify().is_ok());

    assert_eq!(return_instruction.get_num_operands(), 0);
    assert!(return_instruction.get_operand(0).is_none());
    assert!(return_instruction.get_operand(1).is_none());
    assert!(return_instruction.get_operand(2).is_none());

    // Test Uses
    let bitcast_use_value = free_operand0_instruction
        .get_first_use()
        .unwrap()
        .get_used_value()
        .left()
        .unwrap();
    let free_call_param = free_instruction.get_operand(0).unwrap().left().unwrap();

    assert_eq!(bitcast_use_value, free_call_param);

    // These instructions/calls don't return any ir value so they aren't used anywhere
    assert!(store_instruction.get_first_use().is_none());
    assert!(free_instruction.get_first_use().is_none());
    assert!(return_instruction.get_first_use().is_none());

    // arg1 (%0) has two uses:
    //   store float 0x400921FB60000000, float* %0
    //   %1 = bitcast float* %0 to i8*
    let arg1_first_use = arg1.get_first_use().unwrap();
    let arg1_second_use = arg1_first_use.get_next_use().unwrap();

    // However their operands are used
    let store_operand_use0 = store_instruction.get_operand_use(0).unwrap();
    let store_operand_use1 = store_instruction.get_operand_use(1).unwrap();

    assert!(store_operand_use0.get_next_use().is_none());
    assert!(store_operand_use1.get_next_use().is_none());
    assert_eq!(store_operand_use1, arg1_second_use);

    assert_eq!(store_operand_use0.get_user(), store_instruction);
    assert_eq!(store_operand_use1.get_user(), store_instruction);
    assert_eq!(store_operand_use0.get_used_value().left().unwrap(), f32_val);
    assert_eq!(store_operand_use1.get_used_value().left().unwrap(), arg1);

    assert!(store_instruction.get_operand_use(2).is_none());
    assert!(store_instruction.get_operand_use(3).is_none());
    assert!(store_instruction.get_operand_use(4).is_none());
    assert!(store_instruction.get_operand_use(5).is_none());
    assert!(store_instruction.get_operand_use(6).is_none());

    let free_operand_use0 = free_instruction.get_operand_use(0).unwrap();
    let free_operand_use1 = free_instruction.get_operand_use(1).unwrap();

    assert!(free_operand_use0.get_next_use().is_none());
    assert!(free_operand_use1.get_next_use().is_none());
    assert!(free_instruction.get_operand_use(2).is_none());
    assert!(free_instruction.get_operand_use(3).is_none());
    assert!(free_instruction.get_operand_use(4).is_none());
    assert!(free_instruction.get_operand_use(5).is_none());
    assert!(free_instruction.get_operand_use(6).is_none());

    assert!(module.verify().is_ok());
}

#[test]
fn test_basic_block_operand() {
    let context = Context::create();
    let module = context.create_module("ivs");
    let builder = context.create_builder();
    let void_type = context.void_type();
    let fn_type = void_type.fn_type(&[], false);
    let function = module.add_function("bb_op", fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");
    let basic_block2 = context.append_basic_block(&function, "exit");

    builder.position_at_end(&basic_block);

    let branch_instruction = builder.build_unconditional_branch(&basic_block2);
    let bb_operand = branch_instruction.get_operand(0).unwrap().right().unwrap();

    assert_eq!(bb_operand, basic_block2);

    let bb_operand_use = branch_instruction.get_operand_use(0).unwrap();

    assert_eq!(bb_operand_use.get_used_value().right().unwrap(), basic_block2);

    builder.position_at_end(&basic_block2);
    builder.build_return(None);

    assert!(module.verify().is_ok());
}

#[test]
fn test_get_next_use() {
    let context = Context::create();
    let module = context.create_module("ivs");
    let builder = context.create_builder();
    let f32_type = context.f32_type();
    let fn_type = f32_type.fn_type(&[f32_type.into()], false);
    let function = module.add_function("take_f32", fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");

    builder.position_at_end(&basic_block);

    let arg1 = function.get_first_param().unwrap().into_float_value();
    let f32_val = f32_type.const_float(::std::f64::consts::PI);
    let add_pi0 = builder.build_float_add(arg1, f32_val, "add_pi");
    let add_pi1 = builder.build_float_add(add_pi0, f32_val, "add_pi");

    builder.build_return(Some(&add_pi1));

    // f32_val constant appears twice, so there are two uses (first, next)
    let first_use = f32_val.get_first_use().unwrap();

    assert_eq!(first_use.get_user(), add_pi1.as_instruction_value().unwrap());
    assert_eq!(first_use.get_next_use().map(|x| x.get_user()), add_pi0.as_instruction_value());
    assert!(arg1.get_first_use().is_some());
    assert!(module.verify().is_ok());
}

#[test]
fn test_instructions() {
    let context = Context::create();
    let module = context.create_module("testing");
    let builder = context.create_builder();

    let void_type = context.void_type();
    let i64_type = context.i64_type();
    let f32_type = context.f32_type();
    let f32_ptr_type = f32_type.ptr_type(AddressSpace::Generic);
    let fn_type = void_type.fn_type(&[f32_ptr_type.into(), f32_type.into()], false);

    let function = module.add_function("free_f32", fn_type, None);
    let basic_block = context.append_basic_block(&function, "entry");

    builder.position_at_end(&basic_block);

    let arg1 = function.get_first_param().unwrap().into_pointer_value();
    let arg2 = function.get_nth_param(1).unwrap().into_float_value();

    assert!(arg1.get_first_use().is_none());
    assert!(arg2.get_first_use().is_none());

    let f32_val = f32_type.const_float(::std::f64::consts::PI);

    let store_instruction = builder.build_store(arg1, f32_val);
    let ptr_val = builder.build_ptr_to_int(arg1, i64_type, "ptr_val");
    let ptr = builder.build_int_to_ptr(ptr_val, f32_ptr_type, "ptr");
    let icmp = builder.build_int_compare(IntPredicate::EQ, ptr_val, ptr_val, "icmp");
    let f32_sum = builder.build_float_add(arg2, f32_val, "f32_sum");
    let fcmp = builder.build_float_compare(FloatPredicate::OEQ, f32_sum, arg2, "fcmp");
    let free_instruction = builder.build_free(arg1);
    let return_instruction = builder.build_return(None);

    assert_eq!(store_instruction.get_opcode(), Store);
    assert_eq!(ptr_val.as_instruction().unwrap().get_opcode(), PtrToInt);
    assert_eq!(ptr.as_instruction().unwrap().get_opcode(), IntToPtr);
    assert_eq!(icmp.as_instruction().unwrap().get_opcode(), ICmp);
    assert_eq!(ptr.as_instruction().unwrap().get_icmp_predicate(), None);
    assert_eq!(icmp.as_instruction().unwrap().get_icmp_predicate().unwrap(), IntPredicate::EQ);
    assert_eq!(f32_sum.as_instruction().unwrap().get_opcode(), FAdd);
    assert_eq!(fcmp.as_instruction().unwrap().get_opcode(), FCmp);
    assert_eq!(f32_sum.as_instruction().unwrap().get_fcmp_predicate(), None);
    assert_eq!(icmp.as_instruction().unwrap().get_fcmp_predicate(), None);
    assert_eq!(fcmp.as_instruction().unwrap().get_fcmp_predicate().unwrap(), FloatPredicate::OEQ);
    assert_eq!(free_instruction.get_opcode(), Call);
    assert_eq!(return_instruction.get_opcode(), Return);

    // test instruction cloning
    let instruction_clone = return_instruction.clone();

    assert_eq!(instruction_clone.get_opcode(), return_instruction.get_opcode());
    assert_ne!(instruction_clone, return_instruction);

    // test copying
    let instruction_clone_copy = instruction_clone;

    assert_eq!(instruction_clone, instruction_clone_copy);
}
<|endoftext|>


<commit_before>// ! Spit string with a delimeter.

// xxx

pub( crate ) mod internal
{

  /* xxx : qqq : tab after git sync */

  // use woptions::*; /* xxx : use prelude */
  use crate::string::parse::OpType;

  ///
  /// Either delimeter or delimeted with the slice on its string.
  ///

  #[allow(dead_code)]
  #[ derive( Debug ) ]
  pub struct Split< 'a >
  {
    string : &'a str,
    typ : SplitType,
  }

  impl< 'a > From< Split< 'a > > for String
  {
    fn from( src : Split ) -> Self
    {
      src.string.into()
    }
  }

  ///
  /// Either delimeter or delimeted
  ///

  #[ derive( Debug ) ]
  pub enum SplitType
  {
    /// Substring of the original string with text inbetween delimeters.
    Delimeted,
    /// Delimeter.
    Delimeter,
  }

  ///
  /// Find first match in the string.
  ///

  pub trait Searcher
  {
    /// Find positions of delimeter.
    fn pos( &self, src : &str ) -> Option< ( usize, usize ) >;
  }

  impl Searcher for &str
  {
    fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
    {
      src.find( self ).map( | start | ( start, start + self.len() ) )
    }
  }

  impl Searcher for String
  {
    fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
    {
      src.find( self ).map( | start | ( start, start + self.len() ) )
    }
  }

  impl Searcher for Vec<&str>
  {
    fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
    {
      let mut r = vec![];
      for pat in self
      {
        match src.find( pat )
        {
          Some( x ) => r.push( ( x, x + pat.len() ) ),
          None => (),
        }
      }

      if r.is_empty()
      {
        return None;
      }

      r.into_iter().reduce( | accum, item |
      {
        if accum.0 > item.0
        {
          item
        }
        else
        {
          if accum.1 > item.1
          {
            item
          }
          else
          {
            accum
          }
        }
      })
    }
  }

  ///
  /// Split iterator.
  ///

  #[ derive( Debug ) ]
  pub struct SplitFastIterator< 'a, D >
  where
    D : Searcher
  {
    iterable : &'a str,
    counter : i32,
    delimeter : D,
    preserving_empty : bool,
    preserving_delimeters : bool,
    stop_empty : bool,
  }

  //

  impl< 'a, D : Searcher > SplitFastIterator< 'a, D >
  {
    #[ allow( dead_code ) ]
    fn new
    (
      src : &'a str,
      delimeter : D,
      preserving_empty : bool,
      preserving_delimeters : bool,
    ) -> Self
    {
      Self
      {
        iterable : src,
        delimeter,
        counter : 0,
        preserving_empty,
        preserving_delimeters,
        stop_empty : false,
      }
    }
  }

  //

  impl< 'a, D > Iterator for SplitFastIterator< 'a, D >
  where
    D : Searcher
  {
    type Item = Split< 'a >;

    fn next( &mut self ) -> Option< Self::Item >
    {
      self.counter += 1;

      if self.counter % 2 == 1
      {
        let positions = self.delimeter.pos( self.iterable );
        if let Some( ( mut start, end ) ) = positions
        {
          if self.iterable == "" && start == end
          {
            if self.stop_empty
            {
              return None;
            }
            else
            {
              self.counter -= 1;
              self.stop_empty = true;
              return Some( Split { string : "", typ : SplitType::Delimeted } );
            }
          }
          let mut next = &self.iterable[ ..start ];
          if start == end
          {
            if self.counter >= 3
            {
              next = &self.iterable[ ..start + 1 ];
              start += 1;
            }
          }

          self.iterable = &self.iterable[ start.. ];

          Some( Split { string : next, typ : SplitType::Delimeted } )
        }
        else
        {
          return self.next_end_split();
        }
      }
      else
      {
        if self.delimeter.pos( self.iterable ).is_none()
        {
          self.iterable = "";
          return None;
        }

        let ( start, end ) = self.delimeter.pos( self.iterable ).unwrap();
        let string = &self.iterable[ start..end ];
        self.iterable = &self.iterable[ end.. ];

        if self.preserving_delimeters
        {
          return Some( Split { string, typ : SplitType::Delimeter } );
        }
        else
        {
          return self.next_odd_split();
        }
      }
    }
  }

  impl< 'a, D > SplitFastIterator< 'a, D >
  where
    D : Searcher
  {
    fn next_end_split( &mut self ) -> Option< Split< 'a > >
    {
      if self.iterable == ""
      {
        return None;
      }
      else
      {
        let r = Split { string : self.iterable, typ : SplitType::Delimeted };
        self.iterable = "";
        return Some( r );
      }
    }

    fn next_odd_split( &mut self ) -> Option< Split< 'a > >
    {
      match self.delimeter.pos( self.iterable )
      {
        Some( ( start, mut end ) ) =>
        {
          let mut string = &self.iterable[ ..start ];

          if start == end
          {
            string = &self.iterable[ ..start + 1 ];
            end += 1;
          }
          self.iterable = &self.iterable[ end.. ];
          return Some( Split { string, typ : SplitType::Delimeted } );
        },
        None =>
        {
          self.next_end_split()
        },
      }
    }
  }

  ///
  /// Split iterator.
  ///

  #[ derive( Debug ) ]
  pub struct SplitIterator< 'a, D >
  where
    D : Searcher
  {
    iterator : SplitFastIterator< 'a, D >,
    counter : usize,
    stripping : bool,
  }

  //

  impl< 'a, D : Searcher > SplitIterator< 'a, D >
  {
    fn new
    (
      src : &'a str,
      delimeter : D,
      preserving_empty : bool,
      preserving_delimeters : bool,
      stripping : bool,
    ) -> Self
    {
      let iterator = SplitFastIterator
      {
        iterable : src,
        delimeter,
        counter : 0,
        preserving_empty,
        preserving_delimeters,
        stop_empty : false,
      };

      Self
      {
        iterator,
        counter : 0,
        stripping,
      }
    }
  }

  impl< 'a, D > Iterator for SplitIterator< 'a, D >
  where
    D : Searcher
  {
    type Item = Split< 'a >;

    fn next( &mut self ) -> Option< Self::Item >
    {
      self.counter += 1;

      if let Some( mut split ) = self.iterator.next()
      {
        if self.stripping
        {
          split.string = split.string.trim();
          if !self.iterator.preserving_empty && split.string.is_empty() && self.counter % 2 == 0
          {
            self.counter += 1;
            return self.iterator.next();
          }
        }
        Some( split )
      }
      else
      {
        None
      }
    }
  }

  ///
  /// Options of function split.
  ///

  #[ derive( Debug ) ]
  pub struct SplitOptions< 'a, D >
  where
    D : Searcher + Default + Clone,
  {
    src : &'a str,
    delimeter : D,
    preserving_empty : bool,
    preserving_delimeters : bool,
    stripping : bool,
  }

  ///
  /// Adapter for Split Options.
  ///

  pub trait SplitOptionsAdapter< 'a, D >
  {
    /// A string to split.
    fn src( &self ) -> &'a str;
    /// A delimeter to split string.
    fn delimeter( &self ) -> D;
    /// Preserving or dropping empty splits.
    fn preserving_empty( &self ) -> bool;
    /// Preserving or dropping delimeters.
    fn preserving_delimeters( &self ) -> bool;
    /// Stripping.
    fn stripping( &self ) -> bool;
    /// Do splitting.
    fn split( self ) -> SplitIterator< 'a, D >
    where
      Self : Sized,
      D : Searcher + Default,
    {
      SplitIterator::new
      (
        self.src(),
        self.delimeter(),
        self.preserving_empty(),
        self.preserving_delimeters(),
        self.stripping()
      )
    }
  }

  //

  impl< 'a, D > SplitOptionsAdapter< 'a, D > for SplitOptions< 'a, D >
  where
    D : Searcher + Default + Clone,
  {
    fn src( &self ) -> &'a str
    {
      self.src
    }
    fn delimeter( &self ) -> D
    {
      self.delimeter.clone()
    }
    fn preserving_empty( &self ) -> bool
    {
      self.preserving_empty
    }
    fn preserving_delimeters( &self ) -> bool
    {
      self.preserving_delimeters
    }
    fn stripping( &self ) -> bool
    {
      self.stripping
    }
  }

  //

  macro_rules! builder_impls_from
  {
    ( $name : ident, $( ( $field : ident, $type : ty ) ),* $( , )? ) =>
    {
      impl< 'a > $name< 'a >
      {
        $(
          pub fn $field( &mut self, value : $type ) -> &mut $name< 'a >
          {
            assert!( !self.formed, "Already formed" );
            self.$field = value;
            self
          }
        )*

        pub fn form( &mut self ) -> &mut $name< 'a >
        {
          assert!( !self.formed, "Already formed" );
          self.formed = true;
          self
        }
      }
    }
  }

  ///
  /// Former for SplitOptions.
  ///

  #[ derive( Debug ) ]
  pub struct SplitOptionsFormer< 'a >
  {
    src : &'a str,
    delimeter : OpType< &'a str >,
    preserving_empty : bool,
    preserving_delimeters : bool,
    stripping : bool,
    formed : bool,
  }
  builder_impls_from!
  (
    SplitOptionsFormer,
    ( src, &'a str ),
    ( preserving_empty, bool ),
    ( preserving_delimeters, bool ),
    ( stripping, bool )
  );

  impl< 'a > SplitOptionsFormer< 'a >
  {
    pub fn new< D : Into< OpType< &'a str > > >( delimeter : D ) -> SplitOptionsFormer< 'a >
    {
      let op_vec : OpType<&'a str> = OpType::Vector( vec![] );
      Self
      {
        src : "",
        delimeter : op_vec.append( delimeter.into() ),
        preserving_empty : true,
        preserving_delimeters : true,
        stripping : true,
        formed : false,
      }
    }

    pub fn delimeter< D : Into< OpType< &'a str > > >( &mut self, value : D ) -> &mut SplitOptionsFormer< 'a >
    {
      assert!( !self.formed, "Already formed" );
      let op_vec : OpType<&'a str> = OpType::Vector( vec![] );
      let op : OpType<&'a str> = value.into();
      self.delimeter = op_vec.append( op );
      self
    }

    pub fn perform( &mut self ) -> SplitIterator< 'a, Vec< &'a str > >
    {
      if !self.formed
      {
        self.formed = true;
      }

      let opts = SplitOptions
      {
        src : self.src,
        delimeter : self.delimeter.clone().vector().unwrap(),
        preserving_empty : self.preserving_empty,
        preserving_delimeters : self.preserving_delimeters,
        stripping : self.stripping,
      };
      opts.split()
    }
  }

  ///
  /// Function to split a string.
  ///
  /// It produces former. To convert former into options and run algorithm of splitting call `form()`.
  ///
  /// # Sample
  /// ```
  ///   let iter = wstring_tools::string::split()
  ///   .src( "abc def" )
  ///   .delimeter( " " )
  ///   .perform();
  /// ```

  pub fn split< 'a >() -> SplitOptionsFormer< 'a >
  {
    SplitOptionsFormer::new( < &str >::default() )
  }
}

/// Owned namespace of the module.
pub mod own
{
  use super::internal as i;

  pub use i::Split;
  pub use i::SplitType;
  pub use i::SplitFastIterator;
  pub use i::SplitOptions;
  pub use i::SplitOptionsAdapter;
  pub use i::split;
}

pub use own::*;

/// Exposed namespace of the module.
pub mod exposed
{
  use super::internal as i;

  pub use i::SplitOptionsAdapter;
  pub use i::split;
}

/// Namespace of the module to include with `use module::*`.
pub mod prelude
{
  use super::internal as i;

  pub use i::SplitOptionsAdapter;
}
<commit_msg>Simplify interface of routine `split` use only vectors, extend the routine<commit_after>// ! Spit string with a delimeter.

// xxx

pub( crate ) mod internal
{

  /* xxx : qqq : tab after git sync */

  // use woptions::*; /* xxx : use prelude */
  use crate::string::parse::OpType;

  ///
  /// Either delimeter or delimeted with the slice on its string.
  ///

  #[allow(dead_code)]
  #[ derive( Debug ) ]
  pub struct Split< 'a >
  {
    string : &'a str,
    typ : SplitType,
  }

  impl< 'a > From< Split< 'a > > for String
  {
    fn from( src : Split ) -> Self
    {
      src.string.into()
    }
  }

  ///
  /// Either delimeter or delimeted
  ///

  #[ derive( Debug ) ]
  pub enum SplitType
  {
    /// Substring of the original string with text inbetween delimeters.
    Delimeted,
    /// Delimeter.
    Delimeter,
  }

  ///
  /// Find first match in the string.
  ///

  pub trait Searcher
  {
    /// Find positions of delimeter.
    fn pos( &self, src : &str ) -> Option< ( usize, usize ) >;
  }

  impl Searcher for &str
  {
    fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
    {
      src.find( self ).map( | start | ( start, start + self.len() ) )
    }
  }

  impl Searcher for String
  {
    fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
    {
      src.find( self ).map( | start | ( start, start + self.len() ) )
    }
  }

  impl Searcher for Vec<&str>
  {
    fn pos( &self, src : &str ) -> Option< ( usize, usize ) >
    {
      let mut r = vec![];
      for pat in self
      {
        match src.find( pat )
        {
          Some( x ) => r.push( ( x, x + pat.len() ) ),
          None => (),
        }
      }

      if r.is_empty()
      {
        return None;
      }

      r.into_iter().reduce( | accum, item |
      {
        if accum.0 > item.0
        {
          item
        }
        else
        {
          if accum.1 > item.1
          {
            item
          }
          else
          {
            accum
          }
        }
      })
    }
  }

  ///
  /// Split iterator.
  ///

  #[ derive( Debug ) ]
  pub struct SplitFastIterator< 'a, D >
  where
    D : Searcher
  {
    iterable : &'a str,
    counter : i32,
    delimeter : D,
    preserving_empty : bool,
    preserving_delimeters : bool,
    stop_empty : bool,
  }

  //

  impl< 'a, D : Searcher + Clone > SplitFastIterator< 'a, D >
  {
    #[ allow( dead_code ) ]
    fn new( o : impl SplitOptionsAdapter< 'a, D > ) -> Self
    {
      Self
      {
        iterable : o.src(),
        delimeter : o.delimeter(),
        counter : 0,
        preserving_empty : o.preserving_empty(),
        preserving_delimeters : o.preserving_delimeters(),
        stop_empty : false,
      }
    }
  }

  //

  impl< 'a, D > Iterator for SplitFastIterator< 'a, D >
  where
    D : Searcher
  {
    type Item = Split< 'a >;

    fn next( &mut self ) -> Option< Self::Item >
    {
      self.counter += 1;

      if self.counter % 2 == 1
      {
        let positions = self.delimeter.pos( self.iterable );
        if let Some( ( mut start, end ) ) = positions
        {
          if self.iterable == "" && start == end
          {
            if self.stop_empty
            {
              return None;
            }
            else
            {
              self.counter -= 1;
              self.stop_empty = true;
              return Some( Split { string : "", typ : SplitType::Delimeted } );
            }
          }
          let mut next = &self.iterable[ ..start ];
          if start == end
          {
            if self.counter >= 3
            {
              next = &self.iterable[ ..start + 1 ];
              start += 1;
            }
          }

          self.iterable = &self.iterable[ start.. ];

          Some( Split { string : next, typ : SplitType::Delimeted } )
        }
        else
        {
          return self.next_end_split();
        }
      }
      else
      {
        if self.delimeter.pos( self.iterable ).is_none()
        {
          self.iterable = "";
          return None;
        }

        let ( start, end ) = self.delimeter.pos( self.iterable ).unwrap();
        let string = &self.iterable[ start..end ];
        self.iterable = &self.iterable[ end.. ];

        if self.preserving_delimeters
        {
          return Some( Split { string, typ : SplitType::Delimeter } );
        }
        else
        {
          return self.next_odd_split();
        }
      }
    }
  }

  impl< 'a, D > SplitFastIterator< 'a, D >
  where
    D : Searcher
  {
    fn next_end_split( &mut self ) -> Option< Split< 'a > >
    {
      if self.iterable == ""
      {
        return None;
      }
      else
      {
        let r = Split { string : self.iterable, typ : SplitType::Delimeted };
        self.iterable = "";
        return Some( r );
      }
    }

    fn next_odd_split( &mut self ) -> Option< Split< 'a > >
    {
      match self.delimeter.pos( self.iterable )
      {
        Some( ( start, mut end ) ) =>
        {
          let mut string = &self.iterable[ ..start ];

          if start == end
          {
            string = &self.iterable[ ..start + 1 ];
            end += 1;
          }
          self.iterable = &self.iterable[ end.. ];
          return Some( Split { string, typ : SplitType::Delimeted } );
        },
        None =>
        {
          self.next_end_split()
        },
      }
    }
  }

  ///
  /// Split iterator.
  ///

  #[ derive( Debug ) ]
  pub struct SplitIterator< 'a >
  {
    iterator : SplitFastIterator< 'a, Vec< &'a str > >,
    counter : usize,
    stripping : bool,
  }

  //

  impl< 'a > SplitIterator< 'a >
  {
    fn new( o : impl SplitOptionsAdapter< 'a, Vec< &'a str > > ) -> Self
    {
      let iterator;
      if !o.stripping() && !o.quoting() /* && !onDelimeter */
      {
        iterator = SplitFastIterator
        {
          iterable : o.src(),
          delimeter : o.delimeter(),
          counter : 0,
          preserving_empty : o.preserving_empty(),
          preserving_delimeters : o.preserving_delimeters(),
          stop_empty : false,
        };
      }
      else
      {
        let mut delimeter;
        if o.quoting()
        {
          delimeter = vec![ "\"", "`", "'" ];
          delimeter.extend( vec![ "\"", "`", "'" ] );
          delimeter.extend( o.delimeter() );
        }
        else
        {
          delimeter = o.delimeter();
        }

        iterator = SplitFastIterator
        {
          iterable : o.src(),
          delimeter,
          counter : 0,
          preserving_empty : o.preserving_empty(),
          preserving_delimeters : o.preserving_delimeters(),
          // preserving_empty : true,
          // preserving_delimeters : true,
          stop_empty : false,
        };
      }

      Self
      {
        iterator,
        counter : 0,
        stripping : o.stripping(),
      }
    }
  }

  impl< 'a > Iterator for SplitIterator< 'a >
  {
    type Item = Split< 'a >;

    fn next( &mut self ) -> Option< Self::Item >
    {
      self.counter += 1;

      if let Some( mut split ) = self.iterator.next()
      {
        if self.stripping
        {
          split.string = split.string.trim();
          if !self.iterator.preserving_empty && split.string.is_empty() && self.counter % 2 == 0
          {
            self.counter += 1;
            return self.iterator.next();
          }
        }
        Some( split )
      }
      else
      {
        None
      }
    }
  }

  ///
  /// Options of function split.
  ///

  #[ derive( Debug ) ]
  pub struct SplitOptions< 'a, D >
  where
    D : Searcher + Default + Clone,
  {
    src : &'a str,
    delimeter : D,
    preserving_empty : bool,
    preserving_delimeters : bool,
    stripping : bool,
    quoting : bool,
  }

  impl< 'a > SplitOptions< 'a, Vec< &'a str > >
  {
    /// Produces SplitIterator.
    pub fn split( self ) -> SplitIterator< 'a >
    where
      Self : Sized,
    {
      SplitIterator::new( self )
    }
  }

  impl< 'a, D > SplitOptions< 'a, D >
  where
    D : Searcher + Default + Clone
  {
    /// Produces SplitFastIterator.
    pub fn split_fast( self ) -> SplitFastIterator< 'a, D >
    where
      Self : Sized,
    {
      SplitFastIterator::new( self )
    }
  }

  ///
  /// Adapter for Split Options.
  ///

  pub trait SplitOptionsAdapter< 'a, D >
  where
    D : Clone
  {
    /// A string to split.
    fn src( &self ) -> &'a str;
    /// A delimeter to split string.
    fn delimeter( &self ) -> D;
    /// Preserving or dropping empty splits.
    fn preserving_empty( &self ) -> bool;
    /// Preserving or dropping delimeters.
    fn preserving_delimeters( &self ) -> bool;
    /// Stripping.
    fn stripping( &self ) -> bool;
    /// Quoting.
    fn quoting( &self ) -> bool;
  }

  //

  impl< 'a, D : Searcher + Clone + Default > SplitOptionsAdapter< 'a, D > for SplitOptions< 'a, D >
  {
    fn src( &self ) -> &'a str
    {
      self.src
    }
    fn delimeter( &self ) -> D
    {
      self.delimeter.clone()
    }
    fn preserving_empty( &self ) -> bool
    {
      self.preserving_empty
    }
    fn preserving_delimeters( &self ) -> bool
    {
      self.preserving_delimeters
    }
    fn stripping( &self ) -> bool
    {
      self.stripping
    }
    fn quoting( &self ) -> bool
    {
      self.quoting
    }
  }

  //

  macro_rules! builder_impls_from
  {
    ( $name : ident, $( ( $field : ident, $type : ty ) ),* $( , )? ) =>
    {
      impl< 'a > $name< 'a >
      {
        $(
          pub fn $field( &mut self, value : $type ) -> &mut $name< 'a >
          {
            self.$field = value;
            self
          }
        )*

        pub fn form( &mut self ) -> SplitOptions< 'a, Vec< &'a str > >
        {
          SplitOptions
          {
            src : self.src,
            delimeter : self.delimeter.clone().vector().unwrap(),
            preserving_empty : self.preserving_empty,
            preserving_delimeters : self.preserving_delimeters,
            stripping : self.stripping,
            quoting : self.quoting,
          }
        }
      }
    }
  }

  ///
  /// Former for SplitOptions.
  ///

  #[ derive( Debug ) ]
  pub struct SplitOptionsFormer< 'a >
  {
    src : &'a str,
    delimeter : OpType< &'a str >,
    preserving_empty : bool,
    preserving_delimeters : bool,
    stripping : bool,
    quoting : bool,
  }
  builder_impls_from!
  (
    SplitOptionsFormer,
    ( src, &'a str ),
    ( preserving_empty, bool ),
    ( preserving_delimeters, bool ),
    ( stripping, bool ),
    ( quoting, bool ),
  );

  impl< 'a > SplitOptionsFormer< 'a >
  {
    pub fn new< D : Into< OpType< &'a str > > >( delimeter : D ) -> SplitOptionsFormer< 'a >
    {
      let op_vec : OpType<&'a str> = OpType::Vector( vec![] );
      Self
      {
        src : "",
        delimeter : op_vec.append( delimeter.into() ),
        preserving_empty : true,
        preserving_delimeters : true,
        stripping : true,
        quoting : false,
      }
    }

    pub fn delimeter< D : Into< OpType< &'a str > > >( &mut self, value : D ) -> &mut SplitOptionsFormer< 'a >
    {
      let op_vec : OpType<&'a str> = OpType::Vector( vec![] );
      let op : OpType<&'a str> = value.into();
      self.delimeter = op_vec.append( op );
      self
    }

    pub fn perform( &mut self ) -> SplitIterator< 'a >
    {
      let opts = self.form();
      opts.split()
    }
  }

  ///
  /// Function to split a string.
  ///
  /// It produces former. To convert former into options and run algorithm of splitting call `form()`.
  ///
  /// # Sample
  /// ```
  ///   let iter = wstring_tools::string::split()
  ///   .src( "abc def" )
  ///   .delimeter( " " )
  ///   .perform();
  /// ```

  pub fn split< 'a >() -> SplitOptionsFormer< 'a >
  {
    SplitOptionsFormer::new( < &str >::default() )
  }
}

/// Owned namespace of the module.
pub mod own
{
  use super::internal as i;

  pub use i::Split;
  pub use i::SplitType;
  pub use i::SplitFastIterator;
  pub use i::SplitOptions;
  pub use i::SplitOptionsAdapter;
  pub use i::split;
}

pub use own::*;

/// Exposed namespace of the module.
pub mod exposed
{
  use super::internal as i;

  pub use i::SplitOptionsAdapter;
  pub use i::split;
}

/// Namespace of the module to include with `use module::*`.
pub mod prelude
{
  use super::internal as i;

  pub use i::SplitOptionsAdapter;
}
<|endoftext|>