<commit_before>use std::rc::*;

use rustc_serialize::*;

use super::treenode::*;
use super::values::*;

///
/// Used to help decode tree nodes into other types
///
struct TreeNodeDecoder {
    current_node: Rc<TreeNode>
}

#[derive(Debug)]
pub enum TreeNodeDecodingError {
    UnsupportedType,
    NodeHasInvalidType,
    ValueOutOfRange,
    MissingField,
    GenericError(String)
}

impl TreeNodeDecoder {
    fn read_current(&self) -> &TreeValue {
        self.current_node.get_value()
    }
}

impl Decoder for TreeNodeDecoder {
    type Error = TreeNodeDecodingError;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        match *self.read_current() {
            TreeValue::Nothing  => Ok(()),
            _                   => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i16::min_value() as i32) && (*x <= i16::max_value() as i32) { Ok(*x as i16) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i8::min_value() as i32) && (*x <= i8::max_value() as i32) { Ok(*x as i8) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        match *self.read_current() {
            TreeValue::String(ref x)    => Ok(x.to_owned()),
            _                           => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        match *self.read_current() {
            TreeValue::Bool(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x as f32),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        f(self)
    }

    fn read_struct_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        // Look up the field
        // TODO: could hash the field names to avoid doing a linear search every time (not clear if there are substantial benefits for this given the small number of fields in most structures)
        let field = self.current_node.get_child_ref_at(f_name);

        match field {
            None        => Err(TreeNodeDecodingError::MissingField),
            Some(ref x) => {
                // Move into the field node
                let previous_node = self.current_node.to_owned();
                self.current_node = x.to_owned();

                // Decode it
                let result = f(self);

                // Move back out
                self.current_node = previous_node.to_owned();

                result
            }
        }
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, bool) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn error(&mut self, err: &str) -> Self::Error {
        TreeNodeDecodingError::GenericError(err.to_string())
    }
}
<commit_msg>Add a trait that lets us create new items from trees<commit_after>use std::rc::*;

use rustc_serialize::*;

use super::encoder::*;
use super::treenode::*;
use super::values::*;

///
/// Used to help decode tree nodes into other types
///
struct TreeNodeDecoder {
    current_node: Rc<TreeNode>
}

#[derive(Debug)]
pub enum TreeNodeDecodingError {
    UnsupportedType,
    NodeHasInvalidType,
    ValueOutOfRange,
    MissingField,
    GenericError(String)
}

impl TreeNodeDecoder {
    fn read_current(&self) -> &TreeValue {
        self.current_node.get_value()
    }
}

impl Decoder for TreeNodeDecoder {
    type Error = TreeNodeDecodingError;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        match *self.read_current() {
            TreeValue::Nothing  => Ok(()),
            _                   => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i16::min_value() as i32) && (*x <= i16::max_value() as i32) { Ok(*x as i16) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        match *self.read_current() {
            TreeValue::Int(ref x)   => if (*x >= i8::min_value() as i32) && (*x <= i8::max_value() as i32) { Ok(*x as i8) } else { Err(TreeNodeDecodingError::ValueOutOfRange) },
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        match *self.read_current() {
            TreeValue::String(ref x)    => Ok(x.to_owned()),
            _                           => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        match *self.read_current() {
            TreeValue::Bool(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        match *self.read_current() {
            TreeValue::Real(ref x)  => Ok(*x as f32),
            _                       => Err(TreeNodeDecodingError::NodeHasInvalidType)
        }
    }

    fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        f(self)
    }

    fn read_struct_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        // Look up the field
        // TODO: could hash the field names to avoid doing a linear search every time (not clear if there are substantial benefits for this given the small number of fields in most structures)
        let field = self.current_node.get_child_ref_at(f_name);

        match field {
            None        => Err(TreeNodeDecodingError::MissingField),
            Some(ref x) => {
                // Move into the field node
                let previous_node = self.current_node.to_owned();
                self.current_node = x.to_owned();

                // Decode it
                let result = f(self);

                // Move back out
                self.current_node = previous_node.to_owned();

                result
            }
        }
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum<T, F>(&mut self, name: &str, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_variant_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_enum_struct_variant_field<T, F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple<T, F>(&mut self, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, bool) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_seq_elt<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error> {
        Err(TreeNodeDecodingError::UnsupportedType)
    }

    fn error(&mut self, err: &str) -> Self::Error {
        TreeNodeDecodingError::GenericError(err.to_string())
    }
}

///
/// Trait implemented by things that can be decoded from a tree node
///
pub trait DecodeFromTreeNode : Sized {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &Rc<TreeNode>) -> Result<Self, TreeNodeDecodingError>;
}

impl<T: Decodable + EncodeToTreeNode> DecodeFromTreeNode for T {
    ///
    /// Creates a new object from a tree node
    ///
    fn new_from_tree(tree: &Rc<TreeNode>) -> Result<T, TreeNodeDecodingError> {
        let mut decoder = TreeNodeDecoder { current_node: tree.to_owned() };

        T::decode(&mut decoder)
    }
}
<|endoftext|>


<commit_before>use nix::unistd::*;
use nix::unistd::ForkResult::*;
use nix::sys::signal::*;
use nix::sys::wait::*;
use libc::_exit;

#[test]
fn test_wait_signal() {
    #[allow(unused_variables)]
    let m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
    match fork() {
      Ok(Child) => pause().unwrap_or_else(|_| unsafe { _exit(123) }),
      Ok(Parent { child }) => {
          kill(child, Some(SIGKILL)).ok().expect("Error: Kill Failed");
          assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, SIGKILL, false)));
      },
      // panic, fork should never fail unless there is a serious problem with the OS
      Err(_) => panic!("Error: Fork Failed")
    }
}

#[test]
fn test_wait_exit() {
    #[allow(unused_variables)]
    let m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // Safe: Child only calls `_exit`, which is async-signal-safe.
    match fork() {
      Ok(Child) => unsafe { _exit(12); },
      Ok(Parent { child }) => {
          assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
      },
      // panic, fork should never fail unless there is a serious problem with the OS
      Err(_) => panic!("Error: Fork Failed")
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
// FIXME: qemu-user doesn't implement ptrace on most arches
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ptrace {
    use nix::sys::ptrace;
    use nix::sys::ptrace::ptrace::*;
    use nix::sys::signal::*;
    use nix::sys::wait::*;
    use nix::unistd::*;
    use nix::unistd::ForkResult::*;
    use std::{ptr, process};
    use libc::_exit;

    fn ptrace_child() -> ! {
        // TODO ptrace::traceme will be added in #666
        let _ = ptrace::ptrace(PTRACE_TRACEME, Pid::from_raw(0), ptr::null_mut(), ptr::null_mut());
        // As recommended by ptrace(2), raise SIGTRAP to pause the child
        // until the parent is ready to continue
        let _ = raise(SIGTRAP);
        unsafe { _exit(0) }
    }

    fn ptrace_parent(child: Pid) {
        // Wait for the raised SIGTRAP
        assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP)));
        // We want to test a syscall stop and a PTRACE_EVENT stop
        assert!(ptrace::setoptions(child, PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXIT).is_ok());

        // First, stop on the next system call, which will be exit()
        // TODO ptrace::syscall will be added in #666
        assert!(ptrace::ptrace(PTRACE_SYSCALL, child, ptr::null_mut(), ptr::null_mut()).is_ok());
        assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
        // Then get the ptrace event for the process exiting
        // TODO ptrace::cont will be added in #666
        assert!(ptrace::ptrace(PTRACE_CONT, child, ptr::null_mut(), ptr::null_mut()).is_ok());
        assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, PTRACE_EVENT_EXIT)));
        // Finally get the normal wait() result, now that the process has exited
        assert!(ptrace::ptrace(PTRACE_CONT, child, ptr::null_mut(), ptr::null_mut()).is_ok());
        assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)));
    }

    #[test]
    fn test_wait_ptrace() {
        #[allow(unused_variables)]
        let m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

        match fork() {
            Ok(Child) => ptrace_child(),
            Ok(Parent { child }) => ptrace_parent(child),
            Err(_) => panic!("Error: Fork Failed")
        }
    }
}
<commit_msg>Remove the TODO comments, add unwrap() for ptrace.<commit_after>use nix::unistd::*;
use nix::unistd::ForkResult::*;
use nix::sys::signal::*;
use nix::sys::wait::*;
use libc::_exit;

#[test]
fn test_wait_signal() {
    #[allow(unused_variables)]
    let m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
    match fork() {
      Ok(Child) => pause().unwrap_or_else(|_| unsafe { _exit(123) }),
      Ok(Parent { child }) => {
          kill(child, Some(SIGKILL)).ok().expect("Error: Kill Failed");
          assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, SIGKILL, false)));
      },
      // panic, fork should never fail unless there is a serious problem with the OS
      Err(_) => panic!("Error: Fork Failed")
    }
}

#[test]
fn test_wait_exit() {
    #[allow(unused_variables)]
    let m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // Safe: Child only calls `_exit`, which is async-signal-safe.
    match fork() {
      Ok(Child) => unsafe { _exit(12); },
      Ok(Parent { child }) => {
          assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
      },
      // panic, fork should never fail unless there is a serious problem with the OS
      Err(_) => panic!("Error: Fork Failed")
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
// FIXME: qemu-user doesn't implement ptrace on most arches
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
mod ptrace {
    use nix::sys::ptrace;
    use nix::sys::ptrace::ptrace::*;
    use nix::sys::signal::*;
    use nix::sys::wait::*;
    use nix::unistd::*;
    use nix::unistd::ForkResult::*;
    use std::{ptr, process};
    use libc::_exit;

    fn ptrace_child() -> ! {
        ptrace::ptrace(PTRACE_TRACEME, Pid::from_raw(0), ptr::null_mut(), ptr::null_mut()).unwrap();
        // As recommended by ptrace(2), raise SIGTRAP to pause the child
        // until the parent is ready to continue
        let _ = raise(SIGTRAP);
        unsafe { _exit(0) }
    }

    fn ptrace_parent(child: Pid) {
        // Wait for the raised SIGTRAP
        assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP)));
        // We want to test a syscall stop and a PTRACE_EVENT stop
        assert!(ptrace::setoptions(child, PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXIT).is_ok());

        // First, stop on the next system call, which will be exit()
        assert!(ptrace::ptrace(PTRACE_SYSCALL, child, ptr::null_mut(), ptr::null_mut()).is_ok());
        assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
        // Then get the ptrace event for the process exiting
        assert!(ptrace::ptrace(PTRACE_CONT, child, ptr::null_mut(), ptr::null_mut()).is_ok());
        assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, PTRACE_EVENT_EXIT)));
        // Finally get the normal wait() result, now that the process has exited
        assert!(ptrace::ptrace(PTRACE_CONT, child, ptr::null_mut(), ptr::null_mut()).is_ok());
        assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)));
    }

    #[test]
    fn test_wait_ptrace() {
        #[allow(unused_variables)]
        let m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");

        match fork() {
            Ok(Child) => ptrace_child(),
            Ok(Parent { child }) => ptrace_parent(child),
            Err(_) => panic!("Error: Fork Failed")
        }
    }
}
<|endoftext|>


<commit_before>
use color::{Color, Colorable};
use elmesque::Element;
use graphics::character::CharacterCache;
use label::{self, FontSize};
use position::{Depth, HorizontalAlign, Position, Positionable, VerticalAlign};
use theme::Theme;
use ui::{Ui, UiId};
use widget::{self, Widget};

/// Displays some given text centred within a rectangle.
#[derive(Clone, Debug)]
pub struct Label<'a> {
    text: &'a str,
    pos: Position,
    maybe_h_align: Option<HorizontalAlign>,
    maybe_v_align: Option<VerticalAlign>,
    depth: Depth,
    style: Style,
}

/// The styling for a Label's renderable Element.
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Style {
    maybe_font_size: Option<FontSize>,
    maybe_color: Option<Color>,
}

/// The state to be stored between updates for the Label.
#[derive(Clone, Debug, PartialEq)]
pub struct State(String);

impl<'a> Label<'a> {

    /// Construct a new Label widget.
    pub fn new(text: &'a str) -> Label<'a> {
        Label {
            text: text,
            pos: Position::default(),
            maybe_h_align: None,
            maybe_v_align: None,
            depth: 0.0,
            style: Style::new(),
        }
    }

    /// Set the font size for the label.
    #[inline]
    pub fn font_size(mut self, size: FontSize) -> Label<'a> {
        self.style.maybe_font_size = Some(size);
        self
    }

}

impl<'a> Widget for Label<'a> {
    type State = State;
    type Style = Style;
    fn unique_kind(&self) -> &'static str { "Label" }
    fn init_state(&self) -> State { State(String::new()) }
    fn style(&self) -> Style { self.style.clone() }

    /// Update the state of the Label.
    fn update<C>(self,
                 prev_state: &widget::State<State>,
                 style: &Style,
                 _ui_id: UiId,
                 ui: &mut Ui<C>) -> widget::State<Option<State>>
        where
            C: CharacterCache,
    {
        let widget::State { state: State(ref string), .. } = *prev_state;
        let size = style.font_size(&ui.theme);
        let dim = [label::width(ui, size, self.text), size as f64];
        let h_align = self.maybe_h_align.unwrap_or(ui.theme.align.horizontal);
        let v_align = self.maybe_v_align.unwrap_or(ui.theme.align.vertical);
        let xy = ui.get_xy(self.pos, dim, h_align, v_align);
        let maybe_new_state = if &string[..] != self.text { Some(State(self.text.to_string())) }
                              else { None };
        widget::State { state: maybe_new_state, dim: dim, xy: xy, depth: self.depth }
    }

    /// Construct an Element for the Label.
    fn draw<C>(new_state: &widget::State<State>, style: &Style, ui: &mut Ui<C>) -> Element
        where
            C: CharacterCache,
    {
        use elmesque::form::{text, collage};
        use elmesque::text::Text;
        let widget::State { state: State(ref string), dim, xy, .. } = *new_state;
        let size = style.font_size(&ui.theme);
        let color = style.color(&ui.theme);
        let form = text(Text::from_string(string.clone())
                            .color(color)
                            .height(size as f64)).shift(xy[0].floor(), xy[1].floor());
        collage(dim[0] as i32, dim[1] as i32, vec![form])
    }

    fn enabled(mut self, flag: bool) -> Self {
        //No way to disable inputs, as it doesn't get inputs anyway.
        self
    }
}

impl Style {

    /// Construct the default Style.
    pub fn new() -> Style {
        Style {
            maybe_color: None,
            maybe_font_size: None,
        }
    }

    /// Get the Color for an Element.
    pub fn color(&self, theme: &Theme) -> Color {
        self.maybe_color.unwrap_or(theme.label_color)
    }

    /// Get the label font size for an Element.
    pub fn font_size(&self, theme: &Theme) -> FontSize {
        self.maybe_font_size.unwrap_or(theme.font_size_medium)
    }

}

impl<'a> Colorable for Label<'a> {
    fn color(mut self, color: Color) -> Self {
        self.style.maybe_color = Some(color);
        self
    }
}

impl<'a> Positionable for Label<'a> {
    fn position(mut self, pos: Position) -> Self {
        self.pos = pos;
        self
    }
    #[inline]
    fn horizontal_align(self, h_align: HorizontalAlign) -> Self {
        Label { maybe_h_align: Some(h_align), ..self }
    }
    #[inline]
    fn vertical_align(self, v_align: VerticalAlign) -> Self {
        Label { maybe_v_align: Some(v_align), ..self }
    }
}

<commit_msg>Oops, was giving warnings for unused stuff.<commit_after>
use color::{Color, Colorable};
use elmesque::Element;
use graphics::character::CharacterCache;
use label::{self, FontSize};
use position::{Depth, HorizontalAlign, Position, Positionable, VerticalAlign};
use theme::Theme;
use ui::{Ui, UiId};
use widget::{self, Widget};

/// Displays some given text centred within a rectangle.
#[derive(Clone, Debug)]
pub struct Label<'a> {
    text: &'a str,
    pos: Position,
    maybe_h_align: Option<HorizontalAlign>,
    maybe_v_align: Option<VerticalAlign>,
    depth: Depth,
    style: Style,
}

/// The styling for a Label's renderable Element.
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Style {
    maybe_font_size: Option<FontSize>,
    maybe_color: Option<Color>,
}

/// The state to be stored between updates for the Label.
#[derive(Clone, Debug, PartialEq)]
pub struct State(String);

impl<'a> Label<'a> {

    /// Construct a new Label widget.
    pub fn new(text: &'a str) -> Label<'a> {
        Label {
            text: text,
            pos: Position::default(),
            maybe_h_align: None,
            maybe_v_align: None,
            depth: 0.0,
            style: Style::new(),
        }
    }

    /// Set the font size for the label.
    #[inline]
    pub fn font_size(mut self, size: FontSize) -> Label<'a> {
        self.style.maybe_font_size = Some(size);
        self
    }

}

impl<'a> Widget for Label<'a> {
    type State = State;
    type Style = Style;
    fn unique_kind(&self) -> &'static str { "Label" }
    fn init_state(&self) -> State { State(String::new()) }
    fn style(&self) -> Style { self.style.clone() }

    /// Update the state of the Label.
    fn update<C>(self,
                 prev_state: &widget::State<State>,
                 style: &Style,
                 _ui_id: UiId,
                 ui: &mut Ui<C>) -> widget::State<Option<State>>
        where
            C: CharacterCache,
    {
        let widget::State { state: State(ref string), .. } = *prev_state;
        let size = style.font_size(&ui.theme);
        let dim = [label::width(ui, size, self.text), size as f64];
        let h_align = self.maybe_h_align.unwrap_or(ui.theme.align.horizontal);
        let v_align = self.maybe_v_align.unwrap_or(ui.theme.align.vertical);
        let xy = ui.get_xy(self.pos, dim, h_align, v_align);
        let maybe_new_state = if &string[..] != self.text { Some(State(self.text.to_string())) }
                              else { None };
        widget::State { state: maybe_new_state, dim: dim, xy: xy, depth: self.depth }
    }

    /// Construct an Element for the Label.
    fn draw<C>(new_state: &widget::State<State>, style: &Style, ui: &mut Ui<C>) -> Element
        where
            C: CharacterCache,
    {
        use elmesque::form::{text, collage};
        use elmesque::text::Text;
        let widget::State { state: State(ref string), dim, xy, .. } = *new_state;
        let size = style.font_size(&ui.theme);
        let color = style.color(&ui.theme);
        let form = text(Text::from_string(string.clone())
                            .color(color)
                            .height(size as f64)).shift(xy[0].floor(), xy[1].floor());
        collage(dim[0] as i32, dim[1] as i32, vec![form])
    }

    #[allow(unused_mut, unused_variables)]
    fn enabled(mut self, flag: bool) -> Self {
        //No way to disable inputs, as it doesn't get inputs anyway.
        self
    }
}

impl Style {

    /// Construct the default Style.
    pub fn new() -> Style {
        Style {
            maybe_color: None,
            maybe_font_size: None,
        }
    }

    /// Get the Color for an Element.
    pub fn color(&self, theme: &Theme) -> Color {
        self.maybe_color.unwrap_or(theme.label_color)
    }

    /// Get the label font size for an Element.
    pub fn font_size(&self, theme: &Theme) -> FontSize {
        self.maybe_font_size.unwrap_or(theme.font_size_medium)
    }

}

impl<'a> Colorable for Label<'a> {
    fn color(mut self, color: Color) -> Self {
        self.style.maybe_color = Some(color);
        self
    }
}

impl<'a> Positionable for Label<'a> {
    fn position(mut self, pos: Position) -> Self {
        self.pos = pos;
        self
    }
    #[inline]
    fn horizontal_align(self, h_align: HorizontalAlign) -> Self {
        Label { maybe_h_align: Some(h_align), ..self }
    }
    #[inline]
    fn vertical_align(self, v_align: VerticalAlign) -> Self {
        Label { maybe_v_align: Some(v_align), ..self }
    }
}

<|endoftext|>


<commit_before>#![feature(core,collections)]

extern crate regex;

use regex::Regex;

use std::process::{Command,Output};
use std::str::FromStr;

#[derive(Debug)]
struct CompileResult {
  success: bool,
  errors: Vec<CompileError>
}

impl CompileResult {
  fn new(output: Output) -> Self {
    let re = Regex::new(r"(?m)^(?P<file>.*):(?P<line>\d+):(?:\d+): (?:\d+):(?:\d+) error: (?P<message>.*)$").unwrap();
    let stderr = String::from_utf8(output.stderr).unwrap();

    let mut errors = Vec::<CompileError>::new();

    for capture in re.captures_iter(stderr.as_slice()) {
      let file = capture.name("file").unwrap();
      let line: usize = FromStr::from_str(capture.name("line").unwrap()).unwrap();
      let message = capture.name("message").unwrap();

      errors.push(CompileError::new(file, line, message));
    }

    CompileResult {
      success: output.status.success(),
      errors: errors
    }
  }

  fn success(&self) -> bool {
    self.errors.len() == 0
  }

  fn has_error(&self, message: &str, line: usize) -> bool {
    for error in self.errors.iter() {
      if error.line == line && error.message.find(message).is_some() {
        return true
      }
    }

    false
  }
}

#[derive(Debug)]
struct CompileError {
  file: String,
  line: usize,
  message: String
}

impl CompileError {
  fn new(file: &str, line: usize, message: &str) -> Self {
    CompileError {
      file: String::from_str(file),
      line: line,
      message: String::from_str(message)
    }
  }
}

const ERR_LIFETIME: &'static str = "does not live long enough";

macro_rules! assert_compile_success {
  ($file:expr) => ({
    let result = compile($file);
    assert!(result.success(), "expected compilation of {:?} to success, got: {:?}", $file, result);
    result
  })
}

macro_rules! assert_compile_fail {
  ($file:expr) => ({
    let result = compile($file);
    assert!(!result.success(), "expected compilation of {:?} to fail", $file);
    result
  });
  ($file:expr,$msg:expr,$line:expr) => ({
    let result = compile($file);
    assert!(!result.success(), "expected compilation of {:?} to fail", $file);
    assert_compile_error!(result, $msg, $line);
    result
  });
}

macro_rules! assert_compile_error {
  ($result:expr,$msg:expr,$line:expr) => ({
    if !$result.has_error($msg, $line) {
      panic!("assertion failed: expected error {:?} on line {}, found {:?}", $msg, $line, $result);
    }
  });
}

fn compile(file: &str) -> CompileResult {
  CompileResult::new(
    Command::new("rustc").
      arg("-L").arg("target").
      arg("-L").arg("target/deps").
      arg(format!("tests/compile-tests/{}", file).as_slice()).
      arg("--out-dir").arg("target/compile-tests").
      output().unwrap()
  )
}

#[test]
fn it_should_not_compile_device_list_that_outlives_context() {
  assert_compile_fail!("device_list_outlives_context.rs", ERR_LIFETIME, 6);
}

#[test]
fn it_should_not_compile_device_ref_that_outlives_context() {
  assert_compile_fail!("device_ref_outlives_context.rs", ERR_LIFETIME, 6);
}

#[test]
fn it_should_compile_device_ref_that_outlives_device_list() {
  assert_compile_success!("device_ref_outlives_device_list.rs");
}

#[test]
fn it_should_not_compile_device_iterator_that_outlives_device_list() {
  assert_compile_fail!("device_iterator_outlives_device_list.rs", ERR_LIFETIME, 8);
}

#[test]
fn it_should_not_compile_device_handle_that_outlives_context() {
  assert_compile_fail!("device_handle_outlives_context.rs", ERR_LIFETIME, 6);
}

#[test]
fn it_should_compile_device_handle_that_outlives_device_ref() {
  assert_compile_success!("device_handle_outlives_device_ref.rs");
}

#[test]
fn it_should_not_compile_interface_handle_that_outlives_device_handle() {
  assert_compile_fail!("interface_handle_outlives_device_handle.rs", ERR_LIFETIME, 9);
}
<commit_msg>updates compile tests for Cargo compatibility<commit_after>#![feature(core,collections)]

extern crate regex;

use regex::Regex;

use std::process::{Command,Output};
use std::str::FromStr;

#[derive(Debug)]
struct CompileResult {
  success: bool,
  errors: Vec<CompileError>
}

impl CompileResult {
  fn new(output: Output) -> Self {
    let re = Regex::new(r"(?m)^(?P<file>.*):(?P<line>\d+):(?:\d+): (?:\d+):(?:\d+) error: (?P<message>.*)$").unwrap();
    let stderr = String::from_utf8(output.stderr).unwrap();

    let mut errors = Vec::<CompileError>::new();

    for capture in re.captures_iter(stderr.as_slice()) {
      let file = capture.name("file").unwrap();
      let line: usize = FromStr::from_str(capture.name("line").unwrap()).unwrap();
      let message = capture.name("message").unwrap();

      errors.push(CompileError::new(file, line, message));
    }

    CompileResult {
      success: output.status.success(),
      errors: errors
    }
  }

  fn success(&self) -> bool {
    self.errors.len() == 0
  }

  fn has_error(&self, message: &str, line: usize) -> bool {
    for error in self.errors.iter() {
      if error.line == line && error.message.find(message).is_some() {
        return true
      }
    }

    false
  }
}

#[derive(Debug)]
struct CompileError {
  file: String,
  line: usize,
  message: String
}

impl CompileError {
  fn new(file: &str, line: usize, message: &str) -> Self {
    CompileError {
      file: String::from_str(file),
      line: line,
      message: String::from_str(message)
    }
  }
}

const ERR_LIFETIME: &'static str = "does not live long enough";

macro_rules! assert_compile_success {
  ($file:expr) => ({
    let result = compile($file);
    assert!(result.success(), "expected compilation of {:?} to succeed, got: {:?}", $file, result);
    result
  })
}

macro_rules! assert_compile_fail {
  ($file:expr) => ({
    let result = compile($file);
    assert!(!result.success(), "expected compilation of {:?} to fail", $file);
    result
  });
  ($file:expr,$msg:expr,$line:expr) => ({
    let result = compile($file);
    assert!(!result.success(), "expected compilation of {:?} to fail", $file);
    assert_compile_error!(result, $msg, $line);
    result
  });
}

macro_rules! assert_compile_error {
  ($result:expr,$msg:expr,$line:expr) => ({
    if !$result.has_error($msg, $line) {
      panic!("assertion failed: expected error {:?} on line {}, found {:?}", $msg, $line, $result);
    }
  });
}

fn compile(file: &str) -> CompileResult {
  CompileResult::new(
    Command::new("rustc").
      arg("-L").arg("target/debug").
      arg("-L").arg("target/debug/deps").
      arg(format!("tests/compile-tests/{}", file).as_slice()).
      arg("--out-dir").arg("target/debug/compile-tests").
      output().unwrap()
  )
}

#[test]
fn it_should_not_compile_device_list_that_outlives_context() {
  assert_compile_fail!("device_list_outlives_context.rs", ERR_LIFETIME, 6);
}

#[test]
fn it_should_not_compile_device_ref_that_outlives_context() {
  assert_compile_fail!("device_ref_outlives_context.rs", ERR_LIFETIME, 6);
}

#[test]
fn it_should_compile_device_ref_that_outlives_device_list() {
  assert_compile_success!("device_ref_outlives_device_list.rs");
}

#[test]
fn it_should_not_compile_device_iterator_that_outlives_device_list() {
  assert_compile_fail!("device_iterator_outlives_device_list.rs", ERR_LIFETIME, 8);
}

#[test]
fn it_should_not_compile_device_handle_that_outlives_context() {
  assert_compile_fail!("device_handle_outlives_context.rs", ERR_LIFETIME, 6);
}

#[test]
fn it_should_compile_device_handle_that_outlives_device_ref() {
  assert_compile_success!("device_handle_outlives_device_ref.rs");
}

#[test]
fn it_should_not_compile_interface_handle_that_outlives_device_handle() {
  assert_compile_fail!("interface_handle_outlives_device_handle.rs", ERR_LIFETIME, 9);
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::process::Command;
use std::env;

fn main() {
    let target = env::var("TARGET").expect("Environnement variable TARGET not set");
    // let out_dir = env::var("OUT_DIR").expect("Failed to get output directory");
    let current_dir = env::current_dir().expect("Failed to get current directory");

    // println!("target:      {:?}", target);
    // println!("out_dir:     {:?}", out_dir);
    // println!("current_dir: {:?}", current_dir);

    let libqmlbind_dir = current_dir.join("libqmlbind");
    let libqmlbind_build_dir = libqmlbind_dir.join("build");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to overwrite.");

    let qt_lib_dir = qt_dir.join("lib");
    let qt_bin_dir = qt_dir.join("bin");

    std::fs::create_dir_all(&libqmlbind_build_dir).unwrap_or_else(|e| panic!("Failed to create libqmlbind build directory: {}", e));

    // Initialize git submodule
    if !libqmlbind_dir.join(".git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status()
                                   .unwrap_or_else(|e| panic!("Failed to initialize git submodule: {}", e));
    }

    let output = Command::new(qt_bin_dir.join("qmake")).arg("../qmlbind")
                                      .current_dir(&libqmlbind_build_dir)
                                      .output()
                                      .unwrap_or_else(|e| panic!("Failed execute qmake: {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute qmake process");

    let output = Command::new("make")
                                .current_dir(&libqmlbind_build_dir)
                                .output()
                                .unwrap_or_else(|e| panic!("Failed execute make : {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute make process");

    let output = Command::new("make").arg("staticlib")
                                     .current_dir(&libqmlbind_build_dir)
                                     .output()
                                     .unwrap_or_else(|e| panic!("Failed execute 'make staticlib': {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute 'make staticlib' process");

    println!("cargo:rustc-link-search={}", libqmlbind_build_dir.to_str().unwrap());
    println!("cargo:rustc-link-lib=static=qmlbind");

    let osx_framework = if target.contains("darwin") { "=framework" }
                        else  { "" };
    // On Linux, libraries are name "Qt5Core", not "QtCore" as on OSX
    let linux_qt_lib_ver = if target.contains("linux") { "5" }
                           else  { "" };

    println!("cargo:rustc-link-search{}={}", osx_framework, qt_lib_dir.to_str().unwrap());

    println!("cargo:rustc-link-lib{}=Qt{}Core", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Network", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Gui", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Qml", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Widgets", osx_framework, linux_qt_lib_ver);

    // On Linux, Qt needs icui18n, icuuc and icudata
    if target.contains("linux") {
        println!("cargo:rustc-link-lib=icui18n");
        println!("cargo:rustc-link-lib=icuuc");
        println!("cargo:rustc-link-lib=icudata");
    }

    println!("cargo:rustc-flags=-l stdc++");
}
<commit_msg>libqmlbind-sys: Create build directory _after_ having initialized git submodule<commit_after>use std::path::PathBuf;
use std::process::Command;
use std::env;

fn main() {
    let target = env::var("TARGET").expect("Environnement variable TARGET not set");
    // let out_dir = env::var("OUT_DIR").expect("Failed to get output directory");
    let current_dir = env::current_dir().expect("Failed to get current directory");

    // println!("target:      {:?}", target);
    // println!("out_dir:     {:?}", out_dir);
    // println!("current_dir: {:?}", current_dir);

    let libqmlbind_dir = current_dir.join("libqmlbind");
    let libqmlbind_build_dir = libqmlbind_dir.join("build");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to overwrite.");

    let qt_lib_dir = qt_dir.join("lib");
    let qt_bin_dir = qt_dir.join("bin");

    // Initialize git submodule
    if !libqmlbind_dir.join(".git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status()
                                   .unwrap_or_else(|e| panic!("Failed to initialize git submodule: {}", e));
    }

    std::fs::create_dir_all(&libqmlbind_build_dir).unwrap_or_else(|e| panic!("Failed to create libqmlbind build directory: {}", e));

    let output = Command::new(qt_bin_dir.join("qmake")).arg("../qmlbind")
                                      .current_dir(&libqmlbind_build_dir)
                                      .output()
                                      .unwrap_or_else(|e| panic!("Failed execute qmake: {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute qmake process");

    let output = Command::new("make")
                                .current_dir(&libqmlbind_build_dir)
                                .output()
                                .unwrap_or_else(|e| panic!("Failed execute make : {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute make process");

    let output = Command::new("make").arg("staticlib")
                                     .current_dir(&libqmlbind_build_dir)
                                     .output()
                                     .unwrap_or_else(|e| panic!("Failed execute 'make staticlib': {}", e));
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute 'make staticlib' process");

    println!("cargo:rustc-link-search={}", libqmlbind_build_dir.to_str().unwrap());
    println!("cargo:rustc-link-lib=static=qmlbind");

    let osx_framework = if target.contains("darwin") { "=framework" }
                        else  { "" };
    // On Linux, libraries are name "Qt5Core", not "QtCore" as on OSX
    let linux_qt_lib_ver = if target.contains("linux") { "5" }
                           else  { "" };

    println!("cargo:rustc-link-search{}={}", osx_framework, qt_lib_dir.to_str().unwrap());

    println!("cargo:rustc-link-lib{}=Qt{}Core", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Network", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Gui", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Qml", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Widgets", osx_framework, linux_qt_lib_ver);

    // On Linux, Qt needs icui18n, icuuc and icudata
    if target.contains("linux") {
        println!("cargo:rustc-link-lib=icui18n");
        println!("cargo:rustc-link-lib=icuuc");
        println!("cargo:rustc-link-lib=icudata");
    }

    println!("cargo:rustc-flags=-l stdc++");
}
<|endoftext|>


<commit_before>/*
* Copyright (c) 2016 Alex Crichton
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without
* limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

/*
 * Mles-example client based on Tokio core-connect example.
 */

extern crate mles_utils;
extern crate futures;
extern crate tokio_core;

use std::env;
use std::io::{self, Read, Write};
use std::net::SocketAddr;
use std::thread;

use futures::{Sink, Future, Stream};
use futures::sync::mpsc;
use tokio_core::reactor::Core;
use tokio_core::io::{Io, EasyBuf, Codec};
use tokio_core::net::TcpStream;
use mles_utils::*;

const HDRL: usize = 4;
const KEYL: usize = 8;

fn main() {
    // Parse what address we're going to connect to
    //let addr = env::args().nth(1).unwrap_or_else(|| {
    //    panic!("this program requires at least one argument")
    //});
    let addr = "127.0.0.1:8077";
    let addr = addr.parse::<SocketAddr>().unwrap();

    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let tcp = TcpStream::connect(&addr, &handle);

    // Handle stdin in a separate thread
    let (stdin_tx, stdin_rx) = mpsc::channel(0);
    thread::spawn(|| read_stdin(stdin_tx));
    let stdin_rx = stdin_rx.map_err(|_| panic!()); // errors not possible on rx

    let mut stdout = io::stdout();
    let client = tcp.and_then(|stream| {
        let (sink, stream) = stream.framed(Bytes).split();
        let send_stdin = stdin_rx.forward(sink);
        let write_stdout = stream.for_each(move |buf| {
            let decoded = message_decode(buf.as_slice());
            let mut msg = "".to_string();
            if 0 == decoded.message.len() {
                println!("Error happened");
            }
            else {
                msg.push_str(&decoded.uid);
                msg.push_str(":");
                msg.push_str(String::from_utf8_lossy(decoded.message.as_slice()).into_owned().as_str());
            }
            stdout.write_all(&msg.into_bytes())
        });

        send_stdin.map(|_| ())
        .select(write_stdout.map(|_| ()))
        .then(|_| Ok(()))
    });

    core.run(client).unwrap();
}

struct Bytes;

impl Codec for Bytes {
    type In = EasyBuf;
    type Out = Vec<u8>;

    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<EasyBuf>> {
        if buf.len() >= HDRL { // HDRL is header min size
            if read_hdr_type(buf.as_slice()) != 'M' as u32 {
                let len = buf.len();
                buf.drain_to(len);
                return Ok(None);
            }
            let hdr_len = read_hdr_len(buf.as_slice());
            if 0 == hdr_len {
                let len = buf.len();
                buf.drain_to(len);
                return Ok(None);
            }
            let len = buf.len();
            if len < (HDRL + KEYL + hdr_len) {
                return Ok(None);
            }
            if HDRL + KEYL + hdr_len < len {
                buf.drain_to(HDRL + KEYL);
                return Ok(Some(buf.drain_to(hdr_len)));
            }
            buf.drain_to(HDRL + KEYL);
            Ok(Some(buf.drain_to(hdr_len)))
        } else {
            Ok(None)
        }
    }

    fn encode(&mut self, data: Vec<u8>, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(data);
        Ok(())
    }
}

fn read_stdin(mut rx: mpsc::Sender<Vec<u8>>) {
    let mut stdin = io::stdin();
    let mut stdout = io::stdout();
    /* Set user */
    stdout.write_all(b"User name?\n");
    let mut buf = vec![0; 80];
    let n = match stdin.read(&mut buf) {
        Err(_) |
            Ok(0) => return,
            Ok(n) => n,
    };
    buf.truncate(n-1);
    let userstr = String::from_utf8_lossy(buf.clone().as_slice()).into_owned();

    /* Set channel */
    stdout.write_all(b"Channel?\n");
    let mut buf = vec![0; 80];
    let n = match stdin.read(&mut buf) {
        Err(_) |
            Ok(0) => return,
            Ok(n) => n,
    };
    buf.truncate(n-1);
    let channelstr = String::from_utf8_lossy(buf.clone().as_slice()).into_owned();

    /* Join channel */
    let msg = message_encode(&Msg { uid: userstr.clone(), channel: channelstr.clone(), message: Vec::new() });
    let mut msgv = write_hdr(msg.len());
    let keyv = write_key(0);
    msgv.extend(keyv);
    msgv.extend(msg);
    rx = rx.send(msgv).wait().unwrap();

    let mut msg = userstr.clone();
    msg += "::";
    msg += channelstr.as_str();

    /* Say welcome */
    let mut welcome = "Welcome to ".to_string();
    welcome += msg.as_str();
    welcome += "!\n";
    stdout.write_all(welcome.as_bytes());

    loop {
        let mut buf = vec![0;80];
        let n = match stdin.read(&mut buf) {
            Err(_) |
                Ok(0) => break,
                Ok(n) => n,
        };
        buf.truncate(n);
        let str =  String::from_utf8_lossy(buf.as_slice()).into_owned();
        let msg = message_encode(&Msg { uid: userstr.clone(), channel: channelstr.clone(), message: str.into_bytes() });
        let mut msgv = write_hdr(msg.len());
        let keyv = write_key(0);
        msgv.extend(keyv);
        msgv.extend(msg);
        rx = rx.send(msgv).wait().unwrap();
    }
}

<commit_msg>Fix errorhandling, welcome screen, windows line ends.<commit_after>/*
* Copyright (c) 2016 Alex Crichton
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without
* limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Mles-support (c) Mles developers
*
*/

/*
 * Mles-example client based on Tokio core-connect example.
 */

extern crate mles_utils;
extern crate futures;
extern crate tokio_core;

use std::env;
use std::process;
use std::io::{self, Read, Write};
use std::net::SocketAddr;
use std::thread;

use futures::{Sink, Future, Stream};
use futures::sync::mpsc;
use tokio_core::reactor::Core;
use tokio_core::io::{Io, EasyBuf, Codec};
use tokio_core::net::TcpStream;
use mles_utils::*;

const HDRL: usize = 4;
const KEYL: usize = 8;

fn main() {
    // Parse what address we're going to connect to
    let addr = env::args().nth(1).unwrap_or_else(|| {
        println!("Usage: mles-client <server-address>");
        process::exit(1);
    }
    );
    // add port
    let addr = addr + ":8077";
    let addr = match addr.parse::<SocketAddr>() {
        Ok(addr) => addr,
        Err(err) => {
            println!("Error: {}\nUsage: mles-client <server-address>", err);
            process::exit(1);
        },
    };

    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let tcp = TcpStream::connect(&addr, &handle);

    // Handle stdin in a separate thread
    let (stdin_tx, stdin_rx) = mpsc::channel(0);
    thread::spawn(|| read_stdin(stdin_tx));
    let stdin_rx = stdin_rx.map_err(|_| panic!()); // errors not possible on rx

    let mut stdout = io::stdout();
    let client = tcp.and_then(|stream| {
        stream.set_nodelay(true);
        let (sink, stream) = stream.framed(Bytes).split();
        let send_stdin = stdin_rx.forward(sink);
        let write_stdout = stream.for_each(move |buf| {
            let decoded = message_decode(buf.as_slice());
            let mut msg = "".to_string();
            if 0 == decoded.message.len() {
                println!("Error happened");
            }
            else {
                msg.push_str(&decoded.uid);
                msg.push_str(":");
                msg.push_str(String::from_utf8_lossy(decoded.message.as_slice()).into_owned().as_str());
            }
            stdout.write_all(&msg.into_bytes())
        });

        send_stdin.map(|_| ())
        .select(write_stdout.map(|_| ()))
        .then(|_| Ok(()))
    });

    core.run(client).unwrap();
}

struct Bytes;

impl Codec for Bytes {
    type In = EasyBuf;
    type Out = Vec<u8>;

    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<EasyBuf>> {
        if buf.len() >= HDRL { // HDRL is header min size
            if read_hdr_type(buf.as_slice()) != 'M' as u32 {
                let len = buf.len();
                buf.drain_to(len);
                return Ok(None);
            }
            let hdr_len = read_hdr_len(buf.as_slice());
            if 0 == hdr_len {
                let len = buf.len();
                buf.drain_to(len);
                return Ok(None);
            }
            let len = buf.len();
            if len < (HDRL + KEYL + hdr_len) {
                return Ok(None);
            }
            if HDRL + KEYL + hdr_len < len {
                buf.drain_to(HDRL + KEYL);
                return Ok(Some(buf.drain_to(hdr_len)));
            }
            buf.drain_to(HDRL + KEYL);
            Ok(Some(buf.drain_to(hdr_len)))
        } else {
            Ok(None)
        }
    }

    fn encode(&mut self, data: Vec<u8>, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(data);
        Ok(())
    }
}

fn read_stdin(mut rx: mpsc::Sender<Vec<u8>>) {
    let mut stdin = io::stdin();
    let mut stdout = io::stdout();
    /* Set user */
    stdout.write_all(b"User name?\n");
    let mut buf = vec![0; 80];
    let n = match stdin.read(&mut buf) {
        Err(_) |
            Ok(0) => return,
            Ok(n) => n,
    };
    buf.truncate(n-1);
    let mut userstr = String::from_utf8_lossy(buf.clone().as_slice()).into_owned();
    if userstr.ends_with("\r") {
        let len = userstr.len();
        userstr.truncate(len - 1);
    }

    /* Set channel */
    stdout.write_all(b"Channel?\n");
    let mut buf = vec![0; 80];
    let n = match stdin.read(&mut buf) {
        Err(_) |
            Ok(0) => return,
            Ok(n) => n,
    };
    buf.truncate(n-1);
    let mut channelstr = String::from_utf8_lossy(buf.clone().as_slice()).into_owned();
    if channelstr.ends_with("\r") {
        let len = channelstr.len();
        channelstr.truncate(len - 1);
    }

    /* Join channel */
    let msg = message_encode(&Msg { uid: userstr.clone(), channel: channelstr.clone(), message: Vec::new() });
    let mut msgv = write_hdr(msg.len());
    let keyv = write_key(0);
    msgv.extend(keyv);
    msgv.extend(msg);
    rx = rx.send(msgv).wait().unwrap();

    let mut msg = userstr.clone();
    msg += " to ";
    msg += channelstr.as_str();

    /* Say welcome */
    let mut welcome = "Welcome ".to_string();
    welcome += msg.as_str();
    welcome += "!\n";
    stdout.write_all(welcome.as_bytes());

    loop {
        let mut buf = vec![0;80];
        let n = match stdin.read(&mut buf) {
            Err(_) |
                Ok(0) => break,
                Ok(n) => n,
        };
        buf.truncate(n);
        let str =  String::from_utf8_lossy(buf.as_slice()).into_owned();
        let msg = message_encode(&Msg { uid: userstr.clone(), channel: channelstr.clone(), message: str.into_bytes() });
        let mut msgv = write_hdr(msg.len());
        let keyv = write_key(0);
        msgv.extend(keyv);
        msgv.extend(msg);
        rx = rx.send(msgv).wait().unwrap();
    }
}

<|endoftext|>


<commit_before>use std::fmt::Display;
use thiserror::Error;

fn assert<T: Display>(expected: &str, value: T) {
    assert_eq!(expected, value.to_string());
}

#[test]
fn test_braced() {
    #[derive(Error, Debug)]
    #[error("braced error: {msg}")]
    struct Error {
        msg: String,
    }

    let msg = "T".to_owned();
    assert("braced error: T", Error { msg });
}

#[test]
fn test_braced_unused() {
    #[derive(Error, Debug)]
    #[error("braced error")]
    struct Error {
        extra: usize,
    }

    assert("braced error", Error { extra: 0 });
}

#[test]
fn test_tuple() {
    #[derive(Error, Debug)]
    #[error("tuple error: {0}")]
    struct Error(usize);

    assert("tuple error: 0", Error(0));
}

#[test]
fn test_unit() {
    #[derive(Error, Debug)]
    #[error("unit error")]
    struct Error;

    assert("unit error", Error);
}

#[test]
fn test_enum() {
    #[derive(Error, Debug)]
    enum Error {
        #[error("braced error: {id}")]
        Braced { id: usize },
        #[error("tuple error: {0}")]
        Tuple(usize),
        #[error("unit error")]
        Unit,
    }

    assert("braced error: 0", Error::Braced { id: 0 });
    assert("tuple error: 0", Error::Tuple(0));
    assert("unit error", Error::Unit);
}

#[test]
fn test_constants() {
    #[derive(Error, Debug)]
    #[error("{MSG}: {id:?} (code {CODE:?})")]
    struct Error {
        id: &'static str,
    }

    const MSG: &str = "failed to do";
    const CODE: usize = 9;

    assert("failed to do: \"\" (code 9)", Error { id: "" });
}

#[test]
fn test_inherit() {
    #[derive(Error, Debug)]
    #[error("{0}")]
    enum Error {
        Some(&'static str),
        #[error("other error")]
        Other(&'static str),
    }

    assert("some error", Error::Some("some error"));
    assert("other error", Error::Other("..."));
}

#[test]
fn test_brace_escape() {
    #[derive(Error, Debug)]
    #[error("fn main() {{}}")]
    struct Error;

    assert("fn main() {}", Error);
}

#[test]
fn test_expr() {
    #[derive(Error, Debug)]
    #[error("1 + 1 = {}", 1 + 1)]
    struct Error;
    assert("1 + 1 = 2", Error);
}

#[test]
fn test_nested() {
    #[derive(Error, Debug)]
    #[error("!bool = {}", not(.0))]
    struct Error(bool);

    fn not(bool: &bool) -> bool {
        !*bool
    }

    assert("!bool = false", Error(true));
}

#[test]
fn test_match() {
    #[derive(Error, Debug)]
    #[error("{}: {0}", match .1 {
        Some(n) => format!("error occurred with {}", n),
        None => format!("there was an empty error"),
    })]
    struct Error(String, Option<usize>);

    assert(
        "error occurred with 1: ...",
        Error("...".to_owned(), Some(1)),
    );
    assert(
        "there was an empty error: ...",
        Error("...".to_owned(), None),
    );
}

#[test]
fn test_void() {
    #[derive(Error, Debug)]
    #[error("...")]
    pub enum Error {}
}

#[test]
fn test_mixed() {
    #[derive(Error, Debug)]
    #[error("a={a} :: b={} :: c={c} :: d={d}", 1, c = 2, d = 3)]
    struct Error {
        a: usize,
        d: usize,
    }

    assert("a=0 :: b=1 :: c=2 :: d=3", Error { a: 0, d: 0 });
}

#[test]
fn test_ints() {
    #[derive(Error, Debug)]
    enum Error {
        #[error("error {0}")]
        Tuple(usize, usize),
        #[error("error {0}", '?')]
        Struct { v: usize },
    }

    assert("error 9", Error::Tuple(9, 0));
    assert("error ?", Error::Struct { v: 0 });
}

#[test]
fn test_trailing_comma() {
    #[derive(Error, Debug)]
    #[error(
        "error {0}",
    )]
    #[rustfmt::skip]
    struct Error(char);

    assert("error ?", Error('?'));
}

#[test]
fn test_field() {
    #[derive(Debug)]
    struct Inner {
        data: usize,
    }

    #[derive(Error, Debug)]
    #[error("{}", .0.data)]
    struct Error(Inner);

    assert("0", Error(Inner { data: 0 }));
}

#[test]
fn test_macro_rules() {
    // Regression test for https://github.com/dtolnay/thiserror/issues/86

    macro_rules! decl_error {
        ($variant:ident($value:ident)) => {
            #[derive(Debug, Error)]
            pub enum Error {
                #[error("{0:?}")]
                $variant($value),
            }
        };
    }

    decl_error!(Repro(u8));

    assert("0", Error::Repro(0));
}
<commit_msg>Add failing variation of _0 span test<commit_after>use std::fmt::Display;
use thiserror::Error;

fn assert<T: Display>(expected: &str, value: T) {
    assert_eq!(expected, value.to_string());
}

#[test]
fn test_braced() {
    #[derive(Error, Debug)]
    #[error("braced error: {msg}")]
    struct Error {
        msg: String,
    }

    let msg = "T".to_owned();
    assert("braced error: T", Error { msg });
}

#[test]
fn test_braced_unused() {
    #[derive(Error, Debug)]
    #[error("braced error")]
    struct Error {
        extra: usize,
    }

    assert("braced error", Error { extra: 0 });
}

#[test]
fn test_tuple() {
    #[derive(Error, Debug)]
    #[error("tuple error: {0}")]
    struct Error(usize);

    assert("tuple error: 0", Error(0));
}

#[test]
fn test_unit() {
    #[derive(Error, Debug)]
    #[error("unit error")]
    struct Error;

    assert("unit error", Error);
}

#[test]
fn test_enum() {
    #[derive(Error, Debug)]
    enum Error {
        #[error("braced error: {id}")]
        Braced { id: usize },
        #[error("tuple error: {0}")]
        Tuple(usize),
        #[error("unit error")]
        Unit,
    }

    assert("braced error: 0", Error::Braced { id: 0 });
    assert("tuple error: 0", Error::Tuple(0));
    assert("unit error", Error::Unit);
}

#[test]
fn test_constants() {
    #[derive(Error, Debug)]
    #[error("{MSG}: {id:?} (code {CODE:?})")]
    struct Error {
        id: &'static str,
    }

    const MSG: &str = "failed to do";
    const CODE: usize = 9;

    assert("failed to do: \"\" (code 9)", Error { id: "" });
}

#[test]
fn test_inherit() {
    #[derive(Error, Debug)]
    #[error("{0}")]
    enum Error {
        Some(&'static str),
        #[error("other error")]
        Other(&'static str),
    }

    assert("some error", Error::Some("some error"));
    assert("other error", Error::Other("..."));
}

#[test]
fn test_brace_escape() {
    #[derive(Error, Debug)]
    #[error("fn main() {{}}")]
    struct Error;

    assert("fn main() {}", Error);
}

#[test]
fn test_expr() {
    #[derive(Error, Debug)]
    #[error("1 + 1 = {}", 1 + 1)]
    struct Error;
    assert("1 + 1 = 2", Error);
}

#[test]
fn test_nested() {
    #[derive(Error, Debug)]
    #[error("!bool = {}", not(.0))]
    struct Error(bool);

    fn not(bool: &bool) -> bool {
        !*bool
    }

    assert("!bool = false", Error(true));
}

#[test]
fn test_match() {
    #[derive(Error, Debug)]
    #[error("{}: {0}", match .1 {
        Some(n) => format!("error occurred with {}", n),
        None => format!("there was an empty error"),
    })]
    struct Error(String, Option<usize>);

    assert(
        "error occurred with 1: ...",
        Error("...".to_owned(), Some(1)),
    );
    assert(
        "there was an empty error: ...",
        Error("...".to_owned(), None),
    );
}

#[test]
fn test_void() {
    #[derive(Error, Debug)]
    #[error("...")]
    pub enum Error {}
}

#[test]
fn test_mixed() {
    #[derive(Error, Debug)]
    #[error("a={a} :: b={} :: c={c} :: d={d}", 1, c = 2, d = 3)]
    struct Error {
        a: usize,
        d: usize,
    }

    assert("a=0 :: b=1 :: c=2 :: d=3", Error { a: 0, d: 0 });
}

#[test]
fn test_ints() {
    #[derive(Error, Debug)]
    enum Error {
        #[error("error {0}")]
        Tuple(usize, usize),
        #[error("error {0}", '?')]
        Struct { v: usize },
    }

    assert("error 9", Error::Tuple(9, 0));
    assert("error ?", Error::Struct { v: 0 });
}

#[test]
fn test_trailing_comma() {
    #[derive(Error, Debug)]
    #[error(
        "error {0}",
    )]
    #[rustfmt::skip]
    struct Error(char);

    assert("error ?", Error('?'));
}

#[test]
fn test_field() {
    #[derive(Debug)]
    struct Inner {
        data: usize,
    }

    #[derive(Error, Debug)]
    #[error("{}", .0.data)]
    struct Error(Inner);

    assert("0", Error(Inner { data: 0 }));
}

#[test]
fn test_macro_rules() {
    // Regression test for https://github.com/dtolnay/thiserror/issues/86

    macro_rules! decl_error {
        ($variant:ident($value:ident)) => {
            #[derive(Debug, Error)]
            pub enum Error0 {
                #[error("{0:?}")]
                $variant($value),
            }

            #[derive(Debug, Error)]
            #[error("{0:?}")]
            pub enum Error1 {
                $variant($value),
            }
        };
    }

    decl_error!(Repro(u8));

    assert("0", Error0::Repro(0));
    assert("0", Error1::Repro(0));
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
// #![feature(type_ascription)]
// #![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

extern crate util;

pub use util::*;

use std::intrinsics;

const DEMO_ID: i64 = 0;
const SUBCALL1_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
pub extern "C" fn subcall_1(data: *mut u8) {
    println!("Enter `subcall_1`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL1_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL1_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall_1`");
}

#[no_mangle]
pub extern "C" fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

trait StackMapExt {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo;
}

impl StackMapExt for StackMap {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        debug!("");
        debug!("addr: {:?}", addr);

	if let Some(_base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                debug!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

#[no_mangle]
pub extern "C" fn subcall_3(_data: *mut u8) {
    println!("Start `subcall_3`");
    let unw = unwind_hack::UnwindContext::new();
    let mut cursor = Some(unw.cursor());

    while let Some(c) = cursor {
        let ip = c.get_reg(unwind_hack::UNW_REG_IP).unwrap();
        let sp = c.get_reg(unwind_hack::UNW_REG_SP).unwrap();
        println!("ip: 0x{:x} sp: 0x{:x}", ip, sp);
        let opt_fbase = backtrace_hack::dlinfo_fbase(ip as *const libc::c_void);
        println!("dlinfo_fbase: {:?}", opt_fbase);
        if let Some(fbase) = opt_fbase {
            println!("dlrel ip: 0x{:x}", ip - (fbase as u64));
        }

        let (offset, name) = {
            let mut buf = Vec::with_capacity(256);
            match c.get_proc_name(&mut buf) {
                Err(e) => {
                    println!("failed to .get_proc_name from subcall_3: {:?}", e);
                    cursor = c.step().unwrap();
                    println!("");
                    continue;
                }
                Ok(offset) => (offset, String::from_utf8(buf).unwrap()),
            }
        };
        let map = unsafe { STACK_MAP.get() };
        println!("map:                              {:?}", map);
        println!("ip: 0x{:08x} name: {} offset: {}", ip, name, offset);
        println!("start of fn:  0x{:08x}", ip - offset);
        if let Some(fbase) = opt_fbase {
            println!("rel start of fn:  0x{:08x}", ip - offset - (fbase as u64));
        }
        cursor = c.step().unwrap();
        println!("");
    }
    println!("Finis `subcall_3`");
}

#[cfg(use_backtrace_hack)]
fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use std::path::Path;
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL1_ID as usize] = subcall_1 as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall_1, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall_1, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<commit_msg>moved `map` extraction to outside the stack walk.<commit_after>#![feature(core_intrinsics, patchpoint_call_intrinsic, stackmap_call_intrinsic)]
#![feature(question_mark)]
// #![feature(type_ascription)]
// #![feature(rustc_attrs)]
#![feature(libc)]
#![feature(const_fn)]
#![feature(rustc_private)]
#![allow(unused_features)]

extern crate libc;
#[macro_use] extern crate log;

extern crate util;

pub use util::*;

use std::intrinsics;

const DEMO_ID: i64 = 0;
const SUBCALL1_ID: i64 = 1;
const SUBCALL2_ID: i64 = 2;

#[no_mangle]
pub extern "C" fn subcall_1(data: *mut u8) {
    println!("Enter `subcall_1`");
    unsafe {
        intrinsics::stackmap_call(SUBCALL1_ID, 0, subcall_2, data);
        // intrinsics::patchpoint_call(SUBCALL1_ID, 13, subcall_2, data);
    }
    println!("Finis `subcall_1`");
}

#[no_mangle]
pub extern "C" fn subcall_2(data: *mut u8) {
    println!("Enter `subcall_2`");
    let mut i = 0;
    let mut saw_one = false;
    print!("[");
    let mut datum = unsafe { *data.offset(i) as char };
    while datum != '\0' {
        if saw_one {
            print!(", ");
        }
        print!("{}", datum);
        saw_one = true;
        i += 1;
        datum = unsafe { *data.offset(i) as char };
    }
    println!("]");
    unsafe {
        intrinsics::stackmap_call(SUBCALL2_ID, 0, subcall_3, data);
        // intrinsics::patchpoint_call(SUBCALL2_ID, 13, subcall_3, data);

    }
    println!("Finis `subcall_2`");
}

use self::backtrace_hack::ReturnAddress;
use self::backtrace_hack::dlinfo_fbase;

#[derive(Debug)]
enum FrameInfo<'a> {
    Addr(ReturnAddress),
    StackMap(StackMapFrameInfo<'a>),
}

#[derive(Debug)]
struct StackMapFrameInfo<'a> {
    addr: ReturnAddress,
    patchpoint_id: u64,
    instruction_offset: u32,
    locations: &'a [Location],
    live_outs: &'a [LiveOut],
}

trait StackMapExt {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo;
}

impl StackMapExt for StackMap {
    fn frame_info(&self, addr: ReturnAddress) -> FrameInfo {
        let mut frame_info = None;

        debug!("");
        debug!("addr: {:?}", addr);

	if let Some(_base) = dlinfo_fbase(addr.0) {
            // Okay, we have a base address for the shared object of addr

            // We still need to find the function itself as well as
            // the call-site within it; here's a naive way to do it.
            //
            // FIXME: build structure ahead of time that allows
            // something faster than this linear scan.
            for r in self.records() {
                let fn_address = address_id(r.patchpoint_id()).unwrap();
                let instr_offset = r.instruction_offset() as usize;
                let call_address = fn_address + instr_offset;

                debug!("frame_info addr {:?} \
                                     record {:?} \
                                     fn_address: 0x{:x} \
                                     instr_offset: {:?} \
                                     call_address: 0x{:x} \
                                     delta: {}",
                         addr, r, fn_address, instr_offset, call_address,
                         call_address as isize - (addr.0 as isize));

                if call_address == addr.0 as usize {
                    assert!(frame_info.is_none());
                    frame_info = Some(StackMapFrameInfo {
                        addr: addr,
                        patchpoint_id: r.patchpoint_id(),
                        instruction_offset: r.instruction_offset(),
                        locations: r.locations(),
                        live_outs: r.live_outs(),
                    })
                }
            }
        } else {
            println!("frame_info no fbase for {:?}", addr);
        }

        if let Some(frame_info) = frame_info {
            FrameInfo::StackMap(frame_info)
        } else {
            FrameInfo::Addr(addr)
        }
    }
}

#[no_mangle]
pub extern "C" fn subcall_3(_data: *mut u8) {
    println!("Start `subcall_3`");

    let map = unsafe { STACK_MAP.get() };
    println!("map:                              {:?}", map);

    let unw = unwind_hack::UnwindContext::new();
    let mut cursor = Some(unw.cursor());

    while let Some(c) = cursor {
        let ip = c.get_reg(unwind_hack::UNW_REG_IP).unwrap();
        let sp = c.get_reg(unwind_hack::UNW_REG_SP).unwrap();
        println!("ip: 0x{:x} sp: 0x{:x}", ip, sp);
        let opt_fbase = backtrace_hack::dlinfo_fbase(ip as *const libc::c_void);
        println!("dlinfo_fbase: {:?}", opt_fbase);
        if let Some(fbase) = opt_fbase {
            println!("dlrel ip: 0x{:x}", ip - (fbase as u64));
        }

        let (offset, name) = {
            let mut buf = Vec::with_capacity(256);
            match c.get_proc_name(&mut buf) {
                Err(e) => {
                    println!("failed to .get_proc_name from subcall_3: {:?}", e);
                    cursor = c.step().unwrap();
                    println!("");
                    continue;
                }
                Ok(offset) => (offset, String::from_utf8(buf).unwrap()),
            }
        };
        println!("ip: 0x{:08x} name: {} offset: {}", ip, name, offset);
        println!("start of fn:  0x{:08x}", ip - offset);
        if let Some(fbase) = opt_fbase {
            println!("rel start of fn:  0x{:08x}", ip - offset - (fbase as u64));
        }
        cursor = c.step().unwrap();
        println!("");
    }
    println!("Finis `subcall_3`");
}

#[cfg(use_backtrace_hack)]
fn subcall_3(data: *mut u8) {
    println!("Start `subcall_3`");
    let map = unsafe { STACK_MAP.get() };
    println!("map:                   {:?}", map);
    let addresses = backtrace_hack::backtrace_return_addresses();
    println!("backtrace:             {:?}", addresses);
    let dlinfos = backtrace_hack::backtrace_dlinfos(&addresses);
    println!("backtrace dlinfos:     {:?}", dlinfos);
    let frame_infos: Vec<_> = addresses.iter()
        .map(|a| map.frame_info(*a))
        .collect();
    println!("backtrace frame_infos: {:?}", frame_infos);
    println!("Finis `subcall_3`");
}

fn main() {
    let local: u32 = 0;
    unsafe { MAIN_LOCAL = &local as *const _ as usize; }
    demo().unwrap();
}

#[derive(Debug)]
pub enum DemoError {
    ParseError(elf::ParseError),
    MissingSection(String),
}

impl std::convert::From<elf::ParseError> for DemoError {
    fn from(x: elf::ParseError) -> Self { DemoError::ParseError(x) }
}

use self::llvm_stackmaps::{LiveOut, Location, StackMap};
use std::cell::UnsafeCell;

struct SharedStackMap {
    map: UnsafeCell<Option<StackMap>>
}

impl SharedStackMap {
    /// Initializes the map. Unsafe because it does not attempt to
    /// enforce thread safety in any way: its your own job to make
    /// sure you do this once and only once.
    unsafe fn initialize(&self, map: StackMap) { *self.map.get() = Some(map); }
    const fn new() -> Self { SharedStackMap { map: UnsafeCell::new(None) } }
    unsafe fn get(&self) -> &'static StackMap {
        (*self.map.get()).as_ref().expect("Cannot get an uninitialized stack map")
    }
}

/// I am going to manually ensure that all clients of SharedStackMap access
/// it in solely a read-only fashion.
unsafe impl Sync for SharedStackMap { }

static STACK_MAP: SharedStackMap = SharedStackMap::new();
static mut ADDRESS_IDS: [usize; 3] = [0; 3];
fn address_id(patchpoint_id: u64) -> Option<usize> {
    unsafe {
        if patchpoint_id > ::std::usize::MAX as u64 { return None; }
        let idx = patchpoint_id as usize;
        if idx >= ADDRESS_IDS.len() { return None; }
        Some(ADDRESS_IDS[idx])
    }
}

fn initialize_shared_state() -> Result<(), DemoError> {
    use std::path::Path;
    use self::byteorder::LittleEndian;

    // FIXME: LLVM's stackmap/patchpoint intrinsic API does
    // not embed the identity of the function context where the
    // stackmap/patchpoint.
    //
    // It instead requires each stackmap/patchpoint invocation to
    // include a (globally unique) 64-bit ID, known at compile time.
    //
    // The problem for me is that it means that I have the
    // responsibility of building a mapping from functions to their
    // unique ID's, just so I can map from the return address to the
    // appropriate stackmap record. :(
    //
    // (I do not quite understand why they made this so hard;
    // presumably it is because the stackmap/patchpoint interface was
    // designed for use in JITs, not in AOT compilers.)
    //
    // In any case, for now I can just hardcode a table with the
    // necessary mapping from patchpoint IDs to function addresses.
    // (And hopefully I can hack the Rust backend to generate a table
    // like this automatically, though ensuring the IDs are unique
    // will be a bit harder than what I do here. I guess for that
    // I might as well re-use the SVH approach... we'll cross that
    // bridge when we get to it.)
    unsafe {
        ADDRESS_IDS[DEMO_ID as usize] = demo as usize;
        ADDRESS_IDS[SUBCALL1_ID as usize] = subcall_1 as usize;
        ADDRESS_IDS[SUBCALL2_ID as usize] = subcall_2 as usize;
    }

    // FIXME: this is not a reliable way to extract the executable file path.
    // (look into alternatives)
    let binary = std::env::args().next().unwrap();

    println!("Hello World from {}", binary);

    let path = Path::new(&binary);
    let file = elf::File::open_path(&path)?;

    let stackmap_section = {
        let name = ".llvm_stackmaps".to_string();
        file.get_section(name.clone())
            .ok_or_else(|| DemoError::MissingSection(name))?
    };

    println!("stackmap_section: {:?}", stackmap_section);

    let stack_map = StackMap::read_from::<LittleEndian>(&mut &stackmap_section.data[..]);
    println!("stack_map: {:?}", stack_map);
    let map = stack_map.expect("Cannot do demo without valid stack map");
    unsafe { STACK_MAP.initialize(map); }
    Ok(())
}

#[no_mangle]
// #[rustc_mir(borrowck_graphviz_postflow="/tmp/foo.dot")]
pub fn demo() -> Result<(), DemoError> {
    try!(initialize_shared_state());

    let mut data = vec![b'h', b'e', b'l', b'l', b'o', 0];
    println!("data addr: {:?}", &data as *const _);

    unsafe {
        intrinsics::stackmap_call(DEMO_ID, 0, subcall_1, data.as_mut_ptr());
        // intrinsics::patchpoint_call(DEMO_ID, 13, subcall_1, data.as_mut_ptr());
    }

    println!("Goodbye World");

    Ok(())
}
<|endoftext|>


<commit_before>use rustc_serialize::{Encodable, Encoder};

use core::resolver::Resolve;
use core::{Package, PackageId, Workspace};
use ops;
use util::CargoResult;

const VERSION: u32 = 1;

pub struct OutputMetadataOptions {
    pub features: Vec<String>,
    pub no_default_features: bool,
    pub no_deps: bool,
    pub version: u32,
}

/// Loads the manifest, resolves the dependencies of the project to the concrete
/// used versions - considering overrides - and writes all dependencies in a JSON
/// format to stdout.
pub fn output_metadata(ws: &Workspace,
                       opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
    if opt.version != VERSION {
        bail!("metadata version {} not supported, only {} is currently supported",
              opt.version, VERSION);
    }
    if opt.no_deps {
        metadata_no_deps(ws, opt)
    } else {
        metadata_full(ws, opt)
    }
}

fn metadata_no_deps(ws: &Workspace,
                    _opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
    Ok(ExportInfo {
        packages: vec![try!(ws.current()).clone()],
        resolve: None,
        version: VERSION,
    })
}

fn metadata_full(ws: &Workspace,
                 opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
    let deps = try!(ops::resolve_dependencies(ws,
                                              None,
                                              opt.features.clone(),
                                              opt.no_default_features));
    let (packages, resolve) = deps;

    let packages = try!(packages.package_ids()
                                .map(|i| packages.get(i).map(|p| p.clone()))
                                .collect());

    Ok(ExportInfo {
        packages: packages,
        resolve: Some(MetadataResolve(resolve)),
        version: VERSION,
    })
}

#[derive(RustcEncodable)]
pub struct ExportInfo {
    packages: Vec<Package>,
    resolve: Option<MetadataResolve>,
    version: u32,
}

/// Newtype wrapper to provide a custom `Encodable` implementation.
/// The one from lockfile does not fit because it uses a non-standard
/// format for `PackageId`s
struct MetadataResolve(Resolve);

impl Encodable for MetadataResolve {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        #[derive(RustcEncodable)]
        struct EncodableResolve<'a> {
            root: &'a PackageId,
            nodes: Vec<Node<'a>>,
        }

        #[derive(RustcEncodable)]
        struct Node<'a> {
            id: &'a PackageId,
            dependencies: Vec<&'a PackageId>,
        }

        let resolve = &self.0;
        let encodable = EncodableResolve {
            root: resolve.root(),
            nodes: resolve.iter().map(|id| {
                Node {
                    id: id,
                    dependencies: resolve.deps(id).collect(),
                }
            }).collect(),
        };

        encodable.encode(s)
    }
}
<commit_msg>Don't use Resolve.root in cargo metadata<commit_after>use rustc_serialize::{Encodable, Encoder};

use core::resolver::Resolve;
use core::{Package, PackageId, Workspace};
use ops;
use util::CargoResult;

const VERSION: u32 = 1;

pub struct OutputMetadataOptions {
    pub features: Vec<String>,
    pub no_default_features: bool,
    pub no_deps: bool,
    pub version: u32,
}

/// Loads the manifest, resolves the dependencies of the project to the concrete
/// used versions - considering overrides - and writes all dependencies in a JSON
/// format to stdout.
pub fn output_metadata(ws: &Workspace,
                       opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
    if opt.version != VERSION {
        bail!("metadata version {} not supported, only {} is currently supported",
              opt.version, VERSION);
    }
    if opt.no_deps {
        metadata_no_deps(ws, opt)
    } else {
        metadata_full(ws, opt)
    }
}

fn metadata_no_deps(ws: &Workspace,
                    _opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
    Ok(ExportInfo {
        packages: vec![try!(ws.current()).clone()],
        resolve: None,
        version: VERSION,
    })
}

fn metadata_full(ws: &Workspace,
                 opt: &OutputMetadataOptions) -> CargoResult<ExportInfo> {
    let deps = try!(ops::resolve_dependencies(ws,
                                              None,
                                              opt.features.clone(),
                                              opt.no_default_features));
    let (packages, resolve) = deps;

    let packages = try!(packages.package_ids()
                                .map(|i| packages.get(i).map(|p| p.clone()))
                                .collect());

    Ok(ExportInfo {
        packages: packages,
        resolve: Some(MetadataResolve(resolve, try!(ws.current()).package_id().clone())),
        version: VERSION,
    })
}

#[derive(RustcEncodable)]
pub struct ExportInfo {
    packages: Vec<Package>,
    resolve: Option<MetadataResolve>,
    version: u32,
}

/// Newtype wrapper to provide a custom `Encodable` implementation.
/// The one from lockfile does not fit because it uses a non-standard
/// format for `PackageId`s
struct MetadataResolve(Resolve, PackageId);

impl Encodable for MetadataResolve {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        #[derive(RustcEncodable)]
        struct EncodableResolve<'a> {
            root: &'a PackageId,
            nodes: Vec<Node<'a>>,
        }

        #[derive(RustcEncodable)]
        struct Node<'a> {
            id: &'a PackageId,
            dependencies: Vec<&'a PackageId>,
        }

        let resolve = &self.0;
        let root = &self.1;
        let encodable = EncodableResolve {
            root: root,
            nodes: resolve.iter().map(|id| {
                Node {
                    id: id,
                    dependencies: resolve.deps(id).collect(),
                }
            }).collect(),
        };

        encodable.encode(s)
    }
}
<|endoftext|>