<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::hash;
use digit_slice::{DigitSlice, FromDigits};

/// A wrapper for referencing Noun-like patterns.
#[derive(Copy, Clone)]
pub enum Shape<A, N> {
    Atom(A),
    Cell(N, N),
}

/// A Nock noun, the basic unit of representation.
///
/// A noun is an atom or a cell. An atom is any natural number. A cell is any
/// ordered pair of nouns.
///
/// Atoms are represented by a little-endian byte array of 8-bit digits.
#[derive(Clone, PartialEq, Eq)]
pub struct Noun(Inner);

#[derive(Clone, PartialEq, Eq)]
enum Inner {
    Atom(Rc<Vec<u8>>),
    Cell(Rc<Noun>, Rc<Noun>),
}

pub type NounShape<'a> = Shape<&'a [u8], &'a Noun>;

impl Noun {
    fn get<'a>(&'a self) -> NounShape<'a> {
        match self.0 {
            Inner::Atom(ref v) => Shape::Atom(&v),
            Inner::Cell(ref a, ref b) => Shape::Cell(&*a, &*b),
        }
    }

    /// Pattern-match a noun with shape [p q r].
    ///
    /// The digit sequence shows the branch length of each leaf node in the
    /// expression being matched. 122 has the leftmost leaf 1 step away from
    /// the root and the two leaves on the right both 2 steps away from the
    /// root.
    pub fn get_122<'a>(&'a self) -> Option<(NounShape<'a>, NounShape<'a>, NounShape<'a>)> {
        if let Shape::Cell(ref a, ref b) = self.get() {
            if let Shape::Cell(ref b, ref c) = b.get() {
                return Some((a.get(), b.get(), c.get()));
            }
        }
        None
    }

    /// Pattern-match a noun with shape [[p q] r].
    pub fn get_221<'a>(&'a self) -> Option<(NounShape<'a>, NounShape<'a>, NounShape<'a>)> {
        if let Shape::Cell(ref a, ref c) = self.get() {
            if let Shape::Cell(ref a, ref b) = a.get() {
                return Some((a.get(), b.get(), c.get()));
            }
        }
        None
    }

    /// Memory address or other unique identifier for the noun.
    fn addr(&self) -> usize {
        &*self as *const _ as usize
    }

    /// Build a new atom noun from a little-endian 8-bit digit sequence.
    pub fn atom(digits: &[u8]) -> Noun {
        Noun(Inner::Atom(Rc::new(digits.to_vec())))
    }

    /// Build a new cell noun from two existing nouns.
    pub fn cell(a: Noun, b: Noun) -> Noun {
        Noun(Inner::Cell(Rc::new(a), Rc::new(b)))
    }

    /// Build a noun from a convertible value.
    pub fn from<T: ToNoun>(item: T) -> Noun {
        item.to_noun()
    }

    /// Run a memoizing fold over the noun
    fn fold<'a, F, T>(&'a self, mut f: F) -> T
        where F: FnMut(Shape<&'a [u8], T>) -> T,
              T: Clone
    {
        fn h<'a, F, T>(noun: &'a Noun,
                       memo: &mut HashMap<usize, T>,
                       f: &mut F)
                       -> T
            where F: FnMut(Shape<&'a [u8], T>) -> T,
                  T: Clone
        {
            let key = noun.addr();

            if memo.contains_key(&key) {
                memo.get(&key).unwrap().clone()
            } else {
                let ret = match noun.get() {
                    Shape::Atom(x) => f(Shape::Atom(x)),
                    Shape::Cell(ref a, ref b) => {
                        let a = h(*a, memo, f);
                        let b = h(*b, memo, f);
                        let ret = f(Shape::Cell(a, b));
                        ret
                    }
                };
                memo.insert(key, ret.clone());
                ret
            }
        }

        h(self, &mut HashMap::new(), &mut f)
    }

}

impl hash::Hash for Noun {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        fn f<H: hash::Hasher>(state: &mut H, shape: Shape<&[u8], u64>) -> u64 {
            match shape {
                Shape::Atom(x) => x.hash(state),
                Shape::Cell(a, b) => {
                    a.hash(state);
                    b.hash(state);
                }
            }
            state.finish()
        }
        self.fold(|x| f(state, x))
            .hash(state);
    }
}

/// Trait for types that can convert themselves to a noun.
pub trait ToNoun {
    fn to_noun(&self) -> Noun;
}

impl<T> ToNoun for T where T: DigitSlice
{
    fn to_noun(&self) -> Noun {
        Noun::atom(self.as_digits())
    }
}

/// A trait for types that can be instantiated from a Nock noun.
pub trait FromNoun: Sized {
    /// The associated error.
    type Err;

    /// Try to convert a noun to an instance of the type.
    fn from_noun(n: &Noun) -> Result<Self, Self::Err>;
}

impl<T> FromNoun for T where T: FromDigits {
    type Err = ();

    fn from_noun(n: &Noun) -> Result<Self, Self::Err> {
        match n.get() {
            Shape::Atom(x) => T::from_digits(x).map_err(|_| ()),
            _ => Err(())
        }
    }
}

impl<T, U> FromNoun for (T, U) where T: FromNoun, U: FromNoun {
    type Err = ();

    fn from_noun(n: &Noun) -> Result<Self, Self::Err> {
        match n.get() {
            Shape::Cell(a, b) => {
                let t = try!(T::from_noun(a).map_err(|_| ()));
                let u = try!(U::from_noun(b).map_err(|_| ()));
                Ok((t, u))
            }
            _ => Err(())
        }
    }
}

// TODO: FromNoun for T: FromIterator<U: FromNoun>. Pair impl should give us
// a HashMap derivation then. Use ~-terminated cell sequence as backend.

// TODO: Turn a ~-terminated noun into a vec or an iter. Can fail if the last
// element isn't a ~, and we'll only know when we hit the last element...
// Return type is Option<Vec<&'a Noun>>?

// TODO: ToNoun for T: IntoIterator<U: ToNoun>.

// TODO: FromNoun/ToNoun for String, compatible with cord datatype.

// TODO: FromNoun/ToNoun for signed numbers using the Urbit representation
// convention.

// Into-conversion is only used so that we can put untyped numeric literals in
// the noun-constructing macro and have them typed as unsigned. If the noun
// constructor uses ToNoun, literals are assumed to be i32, which does not map
// to atoms in quite the way we want.
impl Into<Noun> for u64 {
    fn into(self) -> Noun {
        Noun::from(self)
    }
}

/// Macro for noun literals.
///
/// Rust n![1, 2, 3] corresponds to Nock [1 2 3]
#[macro_export]
macro_rules! n {
    [$x:expr, $y:expr] => { $crate::draft::Noun::cell($x.into(), $y.into()) };
    [$x:expr, $y:expr, $($ys:expr),+] => { $crate::draft::Noun::cell($x.into(), n![$y, $($ys),+]) };
}

#[cfg(test)]
mod tests {
    use std::hash;
    use super::Noun;

    #[test]
    fn scratch() {
        let x = Noun::from(123u32);
        assert!(x == Noun::from(123u8));
    }

    fn hash<T: hash::Hash>(t: &T) -> u64 {
        use std::hash::Hasher;
        let mut s = hash::SipHasher::new();
        t.hash(&mut s);
        s.finish()
    }

    #[test]
    fn test_fold() {
        assert_eq!(hash(&n![1, 2, 3]), hash(&n![1, 2, 3]));
        assert!(hash(&n![n![1, 2], 3]) != hash(&n![1, 2, 3]));
        assert!(hash(&n![1, 2, 3]) != hash(&n![1, 2]));
    }
}
<commit_msg>Parsing code with new Noun<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::str;
use std::iter;
use std::hash;
use digit_slice::{DigitSlice, FromDigits};

/// A wrapper for referencing Noun-like patterns.
#[derive(Copy, Clone)]
pub enum Shape<A, N> {
    Atom(A),
    Cell(N, N),
}

/// A Nock noun, the basic unit of representation.
///
/// A noun is an atom or a cell. An atom is any natural number. A cell is any
/// ordered pair of nouns.
///
/// Atoms are represented by a little-endian byte array of 8-bit digits.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Noun(Inner);

#[derive(Clone, PartialEq, Eq, Debug)]
enum Inner {
    Atom(Rc<Vec<u8>>),
    Cell(Rc<Noun>, Rc<Noun>),
}

pub type NounShape<'a> = Shape<&'a [u8], &'a Noun>;

impl Noun {
    fn get<'a>(&'a self) -> NounShape<'a> {
        match self.0 {
            Inner::Atom(ref v) => Shape::Atom(&v),
            Inner::Cell(ref a, ref b) => Shape::Cell(&*a, &*b),
        }
    }

    /// Pattern-match a noun with shape [p q r].
    ///
    /// The digit sequence shows the branch length of each leaf node in the
    /// expression being matched. 122 has the leftmost leaf 1 step away from
    /// the root and the two leaves on the right both 2 steps away from the
    /// root.
    pub fn get_122<'a>
        (&'a self)
         -> Option<(NounShape<'a>, NounShape<'a>, NounShape<'a>)> {
        if let Shape::Cell(ref a, ref b) = self.get() {
            if let Shape::Cell(ref b, ref c) = b.get() {
                return Some((a.get(), b.get(), c.get()));
            }
        }
        None
    }

    /// Pattern-match a noun with shape [[p q] r].
    pub fn get_221<'a>
        (&'a self)
         -> Option<(NounShape<'a>, NounShape<'a>, NounShape<'a>)> {
        if let Shape::Cell(ref a, ref c) = self.get() {
            if let Shape::Cell(ref a, ref b) = a.get() {
                return Some((a.get(), b.get(), c.get()));
            }
        }
        None
    }

    /// Memory address or other unique identifier for the noun.
    fn addr(&self) -> usize {
        &*self as *const _ as usize
    }

    /// Build a new atom noun from a little-endian 8-bit digit sequence.
    pub fn atom(digits: &[u8]) -> Noun {
        Noun(Inner::Atom(Rc::new(digits.to_vec())))
    }

    /// Build a new cell noun from two existing nouns.
    pub fn cell(a: Noun, b: Noun) -> Noun {
        Noun(Inner::Cell(Rc::new(a), Rc::new(b)))
    }

    /// Build a noun from a convertible value.
    pub fn from<T: ToNoun>(item: T) -> Noun {
        item.to_noun()
    }

    /// Run a memoizing fold over the noun
    fn fold<'a, F, T>(&'a self, mut f: F) -> T
        where F: FnMut(Shape<&'a [u8], T>) -> T,
              T: Clone
    {
        fn h<'a, F, T>(noun: &'a Noun,
                       memo: &mut HashMap<usize, T>,
                       f: &mut F)
                       -> T
            where F: FnMut(Shape<&'a [u8], T>) -> T,
                  T: Clone
        {
            let key = noun.addr();

            if memo.contains_key(&key) {
                memo.get(&key).unwrap().clone()
            } else {
                let ret = match noun.get() {
                    Shape::Atom(x) => f(Shape::Atom(x)),
                    Shape::Cell(ref a, ref b) => {
                        let a = h(*a, memo, f);
                        let b = h(*b, memo, f);
                        let ret = f(Shape::Cell(a, b));
                        ret
                    }
                };
                memo.insert(key, ret.clone());
                ret
            }
        }

        h(self, &mut HashMap::new(), &mut f)
    }
}

impl hash::Hash for Noun {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        fn f<H: hash::Hasher>(state: &mut H, shape: Shape<&[u8], u64>) -> u64 {
            match shape {
                Shape::Atom(x) => x.hash(state),
                Shape::Cell(a, b) => {
                    a.hash(state);
                    b.hash(state);
                }
            }
            state.finish()
        }
        self.fold(|x| f(state, x))
            .hash(state);
    }
}

impl iter::FromIterator<Noun> for Noun {
    fn from_iter<T>(iterator: T) -> Self
        where T: IntoIterator<Item = Noun>
    {
        let mut v: Vec<Noun> = iterator.into_iter().collect();
        v.reverse();

        v.into_iter()
         .fold(None, move |acc, i| {
             acc.map_or_else(|| Some(i.clone()),
                             |a| Some(Noun::cell(i.clone(), a)))
         })
         .expect("Can't make noun from empty list")
    }
}

/// Trait for types that can convert themselves to a noun.
pub trait ToNoun {
    fn to_noun(&self) -> Noun;
}

impl<T> ToNoun for T where T: DigitSlice
{
    fn to_noun(&self) -> Noun {
        Noun::atom(self.as_digits())
    }
}

/// A trait for types that can be instantiated from a Nock noun.
pub trait FromNoun: Sized {
    /// The associated error.
    type Err;

    /// Try to convert a noun to an instance of the type.
    fn from_noun(n: &Noun) -> Result<Self, Self::Err>;
}

impl<T> FromNoun for T where T: FromDigits
{
    type Err = ();

    fn from_noun(n: &Noun) -> Result<Self, Self::Err> {
        match n.get() {
            Shape::Atom(x) => T::from_digits(x).map_err(|_| ()),
            _ => Err(()),
        }
    }
}

impl<T, U> FromNoun for (T, U)
    where T: FromNoun,
          U: FromNoun
{
    type Err = ();

    fn from_noun(n: &Noun) -> Result<Self, Self::Err> {
        match n.get() {
            Shape::Cell(a, b) => {
                let t = try!(T::from_noun(a).map_err(|_| ()));
                let u = try!(U::from_noun(b).map_err(|_| ()));
                Ok((t, u))
            }
            _ => Err(()),
        }
    }
}

// TODO: FromNoun for T: FromIterator<U: FromNoun>. Pair impl should give us
// a HashMap derivation then. Use ~-terminated cell sequence as backend.

// TODO: Turn a ~-terminated noun into a vec or an iter. Can fail if the last
// element isn't a ~, and we'll only know when we hit the last element...
// Return type is Option<Vec<&'a Noun>>?

// TODO: ToNoun for T: IntoIterator<U: ToNoun>.

// TODO: FromNoun/ToNoun for String, compatible with cord datatype.

// TODO: FromNoun/ToNoun for signed numbers using the Urbit representation
// convention.

// Into-conversion is only used so that we can put untyped numeric literals in
// the noun-constructing macro and have them typed as unsigned. If the noun
// constructor uses ToNoun, literals are assumed to be i32, which does not map
// to atoms in quite the way we want.
impl Into<Noun> for u64 {
    fn into(self) -> Noun {
        Noun::from(self)
    }
}

/// Macro for noun literals.
///
/// Rust n![1, 2, 3] corresponds to Nock [1 2 3]
#[macro_export]
macro_rules! n {
    [$x:expr, $y:expr] => { $crate::draft::Noun::cell($x.into(), $y.into()) };
    [$x:expr, $y:expr, $($ys:expr),+] => { $crate::draft::Noun::cell($x.into(), n![$y, $($ys),+]) };
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ParseError;

impl str::FromStr for Noun {
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, ParseError> {
        return parse(&mut s.chars().peekable());

        fn parse<I: Iterator<Item = char>>(input: &mut iter::Peekable<I>)
                                           -> Result<Noun, ParseError> {
            eat_space(input);
            match input.peek().map(|&x| x) {
                Some(c) if c.is_digit(10) => parse_atom(input),
                Some(c) if c == '[' => parse_cell(input),
                _ => Err(ParseError),
            }
        }

        /// Parse an atom, a positive integer.
        fn parse_atom<I: Iterator<Item = char>>(input: &mut iter::Peekable<I>)
                                                -> Result<Noun, ParseError> {
            use num::BigUint;
            let mut buf = Vec::new();

            loop {
                if let Some(&c) = input.peek() {
                    if c.is_digit(10) {
                        input.next();
                        buf.push(c);
                    } else if c == '.' {
                        // Dot is used as a sequence separator (*not* as
                        // decimal point). It can show up anywhere in the
                        // digit sequence and will be ignored.
                        input.next();
                    } else if c == '[' || c == ']' || c.is_whitespace() {
                        // Whitespace or cell brackets can terminate the
                        // digit sequence.
                        break;
                    } else {
                        // Anything else in the middle of the digit sequence
                        // is an error.
                        return Err(ParseError);
                    }
                } else {
                    break;
                }
            }

            if buf.len() == 0 {
                return Err(ParseError);
            }

            let num: BigUint = buf.into_iter()
                                  .collect::<String>()
                                  .parse()
                                  .expect("Failed to parse atom");

            Ok(Noun::from(num))
        }

        /// Parse a cell, a bracketed pair of nouns.
        ///
        /// For additional complication, cells can have the form [a b c] which
        /// parses to [a [b c]].
        fn parse_cell<I: Iterator<Item = char>>(input: &mut iter::Peekable<I>)
                                                -> Result<Noun, ParseError> {
            let mut elts = Vec::new();

            if input.next() != Some('[') {
                panic!("Bad cell start");
            }

            // A cell must have at least two nouns in it.
            elts.push(try!(parse(input)));
            elts.push(try!(parse(input)));

            // It can have further trailing nouns.
            loop {
                eat_space(input);
                match input.peek().map(|&x| x) {
                    Some(c) if c.is_digit(10) => {
                        elts.push(try!(parse_atom(input)))
                    }
                    Some(c) if c == '[' => elts.push(try!(parse_cell(input))),
                    Some(c) if c == ']' => {
                        input.next();
                        break;
                    }
                    _ => return Err(ParseError),
                }
            }

            Ok(elts.into_iter().collect())
        }

        fn eat_space<I: Iterator<Item = char>>(input: &mut iter::Peekable<I>) {
            loop {
                match input.peek().map(|&x| x) {
                    Some(c) if c.is_whitespace() => {
                        input.next();
                    }
                    _ => return,
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use std::hash;
    use super::Noun;
    use num::BigUint;

    fn parses(input: &str, output: Noun) {
        assert_eq!(input.parse::<Noun>().ok().expect("Parsing failed"), output);
    }

    #[test]
    fn scratch() {
        let x = Noun::from(123u32);
        assert!(x == Noun::from(123u8));
    }

    fn hash<T: hash::Hash>(t: &T) -> u64 {
        use std::hash::Hasher;
        let mut s = hash::SipHasher::new();
        t.hash(&mut s);
        s.finish()
    }

    #[test]
    fn test_fold() {
        assert_eq!(hash(&n![1, 2, 3]), hash(&n![1, 2, 3]));
        assert!(hash(&n![n![1, 2], 3]) != hash(&n![1, 2, 3]));
        assert!(hash(&n![1, 2, 3]) != hash(&n![1, 2]));
    }

    #[test]
    fn test_parser() {
        use num::traits::Num;

        assert!("".parse::<Noun>().is_err());
        assert!("12ab".parse::<Noun>().is_err());
        assert!("[]".parse::<Noun>().is_err());
        assert!("[1]".parse::<Noun>().is_err());

        parses("0", Noun::from(0u32));
        parses("1", Noun::from(1u32));
        parses("1.000.000", Noun::from(1_000_000u32));

        parses("4294967295", Noun::from(4294967295u32));
        parses("4294967296", Noun::from(4294967296u64));

        parses("999.999.999.999.999.999.999.999.999.999.999.999.999.999.999.\
                999.999.999.999.999",
               Noun::from(BigUint::from_str_radix("999999999999999999999999\
                                                   999999999999999999999999\
                                                   999999999999",
                                                  10)
                              .unwrap()));

        parses("[1 2]", n![1, 2]);
        parses("[1 2 3]", n![1, 2, 3]);
        parses("[1 [2 3]]", n![1, 2, 3]);
        parses("[[1 2] 3]", n![n![1, 2], 3]);
    }
}
<|endoftext|>


<commit_before><commit_msg>passing tests<commit_after><|endoftext|>


<commit_before><commit_msg>Add more things<commit_after><|endoftext|>


<commit_before><commit_msg>Unit tests, comments, minor renames<commit_after><|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

pub mod proto;

use crate::proto::admission_control::AdmissionControlStatus as ProtoAdmissionControlStatus;
use failure::prelude::*;
use logger::prelude::*;
use mempool::MempoolAddTransactionStatus;
use proto_conv::{FromProto, IntoProto};
use types::vm_error::VMStatus;

/// AC response status of submit_transaction to clients.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AdmissionControlStatus {
    /// Validator accepted the transaction.
    Accepted = 0,
    /// The sender is blacklisted.
    Blacklisted = 1,
    /// The transaction is rejected, e.g. due to incorrect signature.
    Rejected = 2,
}

impl IntoProto for AdmissionControlStatus {
    type ProtoType = crate::proto::admission_control::AdmissionControlStatus;

    fn into_proto(self) -> Self::ProtoType {
        match self {
            AdmissionControlStatus::Accepted => ProtoAdmissionControlStatus::Accepted,
            AdmissionControlStatus::Blacklisted => ProtoAdmissionControlStatus::Blacklisted,
            AdmissionControlStatus::Rejected => ProtoAdmissionControlStatus::Rejected,
        }
    }
}

impl FromProto for AdmissionControlStatus {
    type ProtoType = crate::proto::admission_control::AdmissionControlStatus;

    fn from_proto(object: Self::ProtoType) -> Result<Self> {
        let ret = match object {
            ProtoAdmissionControlStatus::Accepted => AdmissionControlStatus::Accepted,
            ProtoAdmissionControlStatus::Blacklisted => AdmissionControlStatus::Blacklisted,
            ProtoAdmissionControlStatus::Rejected => AdmissionControlStatus::Rejected,
        };
        Ok(ret)
    }
}

/// Rust structure for SubmitTransactionResponse protobuf definition.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SubmitTransactionResponse {
    /// AC status returned to client if any, it includes can be either error or accepted status.
    pub ac_status: Option<AdmissionControlStatus>,
    /// Mempool error status if any.
    pub mempool_error: Option<MempoolAddTransactionStatus>,
    /// VM error status if any.
    pub vm_error: Option<VMStatus>,
    /// The id of validator associated with this AC.
    pub validator_id: Vec<u8>,
}

impl IntoProto for SubmitTransactionResponse {
    type ProtoType = crate::proto::admission_control::SubmitTransactionResponse;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        if let Some(ac_st) = self.ac_status {
            proto.set_ac_status(ac_st.into_proto());
        } else if let Some(mem_err) = self.mempool_error {
            proto.set_mempool_status(mem_err.into_proto());
        } else if let Some(vm_st) = self.vm_error {
            proto.set_vm_status(vm_st.into_proto());
        } else {
            error!("No status is available in SubmitTransactionResponse!");
        }
        proto.set_validator_id(self.validator_id);
        proto
    }
}

impl FromProto for SubmitTransactionResponse {
    type ProtoType = crate::proto::admission_control::SubmitTransactionResponse;

    fn from_proto(mut object: Self::ProtoType) -> Result<Self> {
        let ac_status = if object.has_ac_status() {
            Some(AdmissionControlStatus::from_proto(object.get_ac_status())?)
        } else {
            None
        };
        let mempool_error = if object.has_mempool_status() {
            Some(MempoolAddTransactionStatus::from_proto(
                object.get_mempool_status(),
            )?)
        } else {
            None
        };
        let vm_error = if object.has_vm_status() {
            Some(VMStatus::from_proto(object.take_vm_status())?)
        } else {
            None
        };

        Ok(SubmitTransactionResponse {
            ac_status,
            mempool_error,
            vm_error,
            validator_id: object.take_validator_id(),
        })
    }
}
<commit_msg>Fixing comment on AC status<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

pub mod proto;

use crate::proto::admission_control::AdmissionControlStatus as ProtoAdmissionControlStatus;
use failure::prelude::*;
use logger::prelude::*;
use mempool::MempoolAddTransactionStatus;
use proto_conv::{FromProto, IntoProto};
use types::vm_error::VMStatus;

/// AC response status of submit_transaction to clients.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum AdmissionControlStatus {
    /// Validator accepted the transaction.
    Accepted = 0,
    /// The sender is blacklisted.
    Blacklisted = 1,
    /// The transaction is rejected, e.g. due to incorrect signature.
    Rejected = 2,
}

impl IntoProto for AdmissionControlStatus {
    type ProtoType = crate::proto::admission_control::AdmissionControlStatus;

    fn into_proto(self) -> Self::ProtoType {
        match self {
            AdmissionControlStatus::Accepted => ProtoAdmissionControlStatus::Accepted,
            AdmissionControlStatus::Blacklisted => ProtoAdmissionControlStatus::Blacklisted,
            AdmissionControlStatus::Rejected => ProtoAdmissionControlStatus::Rejected,
        }
    }
}

impl FromProto for AdmissionControlStatus {
    type ProtoType = crate::proto::admission_control::AdmissionControlStatus;

    fn from_proto(object: Self::ProtoType) -> Result<Self> {
        let ret = match object {
            ProtoAdmissionControlStatus::Accepted => AdmissionControlStatus::Accepted,
            ProtoAdmissionControlStatus::Blacklisted => AdmissionControlStatus::Blacklisted,
            ProtoAdmissionControlStatus::Rejected => AdmissionControlStatus::Rejected,
        };
        Ok(ret)
    }
}

/// Rust structure for SubmitTransactionResponse protobuf definition.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct SubmitTransactionResponse {
    /// AC status returned to client if any - it can be one of: accepted, blacklisted, or rejected.
    pub ac_status: Option<AdmissionControlStatus>,
    /// Mempool error status if any.
    pub mempool_error: Option<MempoolAddTransactionStatus>,
    /// VM error status if any.
    pub vm_error: Option<VMStatus>,
    /// The id of validator associated with this AC.
    pub validator_id: Vec<u8>,
}

impl IntoProto for SubmitTransactionResponse {
    type ProtoType = crate::proto::admission_control::SubmitTransactionResponse;

    fn into_proto(self) -> Self::ProtoType {
        let mut proto = Self::ProtoType::new();
        if let Some(ac_st) = self.ac_status {
            proto.set_ac_status(ac_st.into_proto());
        } else if let Some(mem_err) = self.mempool_error {
            proto.set_mempool_status(mem_err.into_proto());
        } else if let Some(vm_st) = self.vm_error {
            proto.set_vm_status(vm_st.into_proto());
        } else {
            error!("No status is available in SubmitTransactionResponse!");
        }
        proto.set_validator_id(self.validator_id);
        proto
    }
}

impl FromProto for SubmitTransactionResponse {
    type ProtoType = crate::proto::admission_control::SubmitTransactionResponse;

    fn from_proto(mut object: Self::ProtoType) -> Result<Self> {
        let ac_status = if object.has_ac_status() {
            Some(AdmissionControlStatus::from_proto(object.get_ac_status())?)
        } else {
            None
        };
        let mempool_error = if object.has_mempool_status() {
            Some(MempoolAddTransactionStatus::from_proto(
                object.get_mempool_status(),
            )?)
        } else {
            None
        };
        let vm_error = if object.has_vm_status() {
            Some(VMStatus::from_proto(object.take_vm_status())?)
        } else {
            None
        };

        Ok(SubmitTransactionResponse {
            ac_status,
            mempool_error,
            vm_error,
            validator_id: object.take_validator_id(),
        })
    }
}
<|endoftext|>


<commit_before>use super::make_command_line;
use crate::env;
use crate::ffi::{OsStr, OsString};
use crate::process::Command;

#[test]
fn test_make_command_line() {
    fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
        let command_line = &make_command_line(
            OsStr::new(prog),
            &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
            force_quotes,
        )
        .unwrap();
        String::from_utf16(command_line).unwrap()
    }

    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");

    assert_eq!(
        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
        "\"C:\\Program Files\\blah\\blah.exe\" aaa"
    );
    assert_eq!(
        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
        "\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
    );
    assert_eq!(
        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
        "\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
    );
    assert_eq!(
        test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
        "\"C:\\Program Files\\test\" aa\\\"bb"
    );
    assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
    assert_eq!(
        test_wrapper("echo", &["\" \\\" \\", "\\"], false),
        "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
    );
    assert_eq!(
        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
        "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
    );
}

// On Windows, environment args are case preserving but comparisons are case-insensitive.
// See: #85242
#[test]
fn windows_env_unicode_case() {
    let test_cases = [
        ("ä", "Ä"),
        ("ß", "SS"),
        ("Ä", "Ö"),
        ("Ä", "Ö"),
        ("I", "İ"),
        ("I", "i"),
        ("I", "ı"),
        ("i", "I"),
        ("i", "İ"),
        ("i", "ı"),
        ("İ", "I"),
        ("İ", "i"),
        ("İ", "ı"),
        ("ı", "I"),
        ("ı", "i"),
        ("ı", "İ"),
        ("ä", "Ä"),
        ("ß", "SS"),
        ("Ä", "Ö"),
        ("Ä", "Ö"),
        ("I", "İ"),
        ("I", "i"),
        ("I", "ı"),
        ("i", "I"),
        ("i", "İ"),
        ("i", "ı"),
        ("İ", "I"),
        ("İ", "i"),
        ("İ", "ı"),
        ("ı", "I"),
        ("ı", "i"),
        ("ı", "İ"),
    ];
    // Test that `cmd.env` matches `env::set_var` when setting two strings that
    // may (or may not) be case-folded when compared.
    for (a, b) in test_cases.iter() {
        let mut cmd = Command::new("cmd");
        cmd.env(a, "1");
        cmd.env(b, "2");
        env::set_var(a, "1");
        env::set_var(b, "2");

        for (key, value) in cmd.get_envs() {
            assert_eq!(
                env::var(key).ok(),
                value.map(|s| s.to_string_lossy().into_owned()),
                "command environment mismatch: {} {}",
                a,
                b
            );
        }
    }
}
<commit_msg>Test escaping of trialing slashes in Windows command-line args<commit_after>use super::make_command_line;
use crate::env;
use crate::ffi::{OsStr, OsString};
use crate::process::Command;

#[test]
fn test_make_command_line() {
    fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
        let command_line = &make_command_line(
            OsStr::new(prog),
            &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
            force_quotes,
        )
        .unwrap();
        String::from_utf16(command_line).unwrap()
    }

    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");

    assert_eq!(test_wrapper("prog", &[r"C:\"], false), r#""prog" C:\"#);
    assert_eq!(test_wrapper("prog", &[r"2slashes\\"], false), r#""prog" 2slashes\\"#);
    assert_eq!(test_wrapper("prog", &[r" C:\"], false), r#""prog" " C:\\""#);
    assert_eq!(test_wrapper("prog", &[r" 2slashes\\"], false), r#""prog" " 2slashes\\\\""#);

    assert_eq!(
        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
        "\"C:\\Program Files\\blah\\blah.exe\" aaa"
    );
    assert_eq!(
        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
        "\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
    );
    assert_eq!(
        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
        "\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
    );
    assert_eq!(
        test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
        "\"C:\\Program Files\\test\" aa\\\"bb"
    );
    assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
    assert_eq!(
        test_wrapper("echo", &["\" \\\" \\", "\\"], false),
        "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
    );
    assert_eq!(
        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
        "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
    );
}

// On Windows, environment args are case preserving but comparisons are case-insensitive.
// See: #85242
#[test]
fn windows_env_unicode_case() {
    let test_cases = [
        ("ä", "Ä"),
        ("ß", "SS"),
        ("Ä", "Ö"),
        ("Ä", "Ö"),
        ("I", "İ"),
        ("I", "i"),
        ("I", "ı"),
        ("i", "I"),
        ("i", "İ"),
        ("i", "ı"),
        ("İ", "I"),
        ("İ", "i"),
        ("İ", "ı"),
        ("ı", "I"),
        ("ı", "i"),
        ("ı", "İ"),
        ("ä", "Ä"),
        ("ß", "SS"),
        ("Ä", "Ö"),
        ("Ä", "Ö"),
        ("I", "İ"),
        ("I", "i"),
        ("I", "ı"),
        ("i", "I"),
        ("i", "İ"),
        ("i", "ı"),
        ("İ", "I"),
        ("İ", "i"),
        ("İ", "ı"),
        ("ı", "I"),
        ("ı", "i"),
        ("ı", "İ"),
    ];
    // Test that `cmd.env` matches `env::set_var` when setting two strings that
    // may (or may not) be case-folded when compared.
    for (a, b) in test_cases.iter() {
        let mut cmd = Command::new("cmd");
        cmd.env(a, "1");
        cmd.env(b, "2");
        env::set_var(a, "1");
        env::set_var(b, "2");

        for (key, value) in cmd.get_envs() {
            assert_eq!(
                env::var(key).ok(),
                value.map(|s| s.to_string_lossy().into_owned()),
                "command environment mismatch: {} {}",
                a,
                b
            );
        }
    }
}
<|endoftext|>


<commit_before>use crate::convert::TryInto;
use crate::fmt;
use crate::io;
use crate::mem;
use crate::ptr;

use crate::sys::process::process_common::*;
use crate::sys::process::zircon::{zx_handle_t, Handle};

use libc::{c_int, size_t};

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(
        &mut self,
        default: Stdio,
        needs_stdin: bool,
    ) -> io::Result<(Process, StdioPipes)> {
        let envp = self.capture_env();

        if self.saw_nul() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "nul byte found in provided data",
            ));
        }

        let (ours, theirs) = self.setup_io(default, needs_stdin)?;

        let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? };

        Ok((Process { handle: Handle::new(process_handle) }, ours))
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        if self.saw_nul() {
            return io::Error::new(io::ErrorKind::InvalidInput, "nul byte found in provided data");
        }

        match self.setup_io(default, true) {
            Ok((_, _)) => {
                // FIXME: This is tough because we don't support the exec syscalls
                unimplemented!();
            }
            Err(e) => e,
        }
    }

    unsafe fn do_exec(
        &mut self,
        stdio: ChildPipes,
        maybe_envp: Option<&CStringArray>,
    ) -> io::Result<zx_handle_t> {
        use crate::sys::process::zircon::*;

        let envp = match maybe_envp {
            // None means to clone the current environment, which is done in the
            // flags below.
            None => ptr::null(),
            Some(envp) => envp.as_ptr(),
        };

        let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> {
            if let Some(local_fd) = local_io.fd() {
                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd,
                    target_fd,
                    ..Default::default()
                })
            } else {
                if let ChildStdio::Null = local_io {
                    // acts as no-op
                    return Ok(Default::default());
                }

                let mut handle = ZX_HANDLE_INVALID;
                let status = fdio_fd_clone(target_fd, &mut handle);
                if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED {
                    // This descriptor is closed; skip it rather than generating an
                    // error.
                    return Ok(Default::default());
                }
                zx_cvt(status)?;

                let mut cloned_fd = 0;
                zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?;

                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd: cloned_fd as i32,
                    target_fd,
                    ..Default::default()
                })
            }
        };

        // Clone stdin, stdout, and stderr
        let action1 = make_action(&stdio.stdin, 0)?;
        let action2 = make_action(&stdio.stdout, 1)?;
        let action3 = make_action(&stdio.stderr, 2)?;
        let actions = [action1, action2, action3];

        // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
        // always consumes transferred file descriptors.
        mem::forget(stdio);

        for callback in self.get_closures().iter_mut() {
            callback()?;
        }

        let mut process_handle: zx_handle_t = 0;
        zx_cvt(fdio_spawn_etc(
            ZX_HANDLE_INVALID,
            FDIO_SPAWN_CLONE_JOB
                | FDIO_SPAWN_CLONE_LDSVC
                | FDIO_SPAWN_CLONE_NAMESPACE
                | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
                | FDIO_SPAWN_CLONE_UTC_CLOCK,
            self.get_program_cstr().as_ptr(),
            self.get_argv().as_ptr(),
            envp,
            actions.len() as size_t,
            actions.as_ptr(),
            &mut process_handle,
            ptr::null_mut(),
        ))?;
        // FIXME: See if we want to do something with that err_msg

        Ok(process_handle)
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

pub struct Process {
    handle: Handle,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.handle.raw() as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        use crate::sys::process::zircon::*;

        unsafe {
            zx_cvt(zx_task_kill(self.handle.raw()))?;
        }

        Ok(())
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            zx_cvt(zx_object_wait_one(
                self.handle.raw(),
                ZX_TASK_TERMINATED,
                ZX_TIME_INFINITE,
                ptr::null_mut(),
            ))?;
            zx_cvt(zx_object_get_info(
                self.handle.raw(),
                ZX_INFO_PROCESS,
                &mut proc_info as *mut _ as *mut libc::c_void,
                mem::size_of::<zx_info_process_t>(),
                &mut actual,
                &mut avail,
            ))?;
        }
        if actual != 1 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Failed to get exit status of process",
            ));
        }
        Ok(ExitStatus(proc_info.return_code))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            let status =
                zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, 0, ptr::null_mut());
            match status {
                0 => {} // Success
                x if x == ERR_TIMED_OUT => {
                    return Ok(None);
                }
                _ => {
                    panic!("Failed to wait on process handle: {}", status);
                }
            }
            zx_cvt(zx_object_get_info(
                self.handle.raw(),
                ZX_INFO_PROCESS,
                &mut proc_info as *mut _ as *mut libc::c_void,
                mem::size_of::<zx_info_process_t>(),
                &mut actual,
                &mut avail,
            ))?;
        }
        if actual != 1 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Failed to get exit status of process",
            ));
        }
        Ok(Some(ExitStatus(proc_info.return_code)))
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(i64);

impl ExitStatus {
    pub fn success(&self) -> bool {
        self.code() == Some(0)
    }

    pub fn code(&self) -> Option<i32> {
        // FIXME: support extracting return code as an i64
        self.0.try_into().ok()
    }

    pub fn signal(&self) -> Option<i32> {
        None
    }
}

/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
impl From<c_int> for ExitStatus {
    fn from(a: c_int) -> ExitStatus {
        ExitStatus(a as i64)
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "exit code: {}", self.0)
    }
}
<commit_msg>ExitStatusExt: Fix build on Fuchsia<commit_after>use crate::convert::TryInto;
use crate::fmt;
use crate::io;
use crate::mem;
use crate::ptr;

use crate::sys::process::process_common::*;
use crate::sys::process::zircon::{zx_handle_t, Handle};

use libc::{c_int, size_t};

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(
        &mut self,
        default: Stdio,
        needs_stdin: bool,
    ) -> io::Result<(Process, StdioPipes)> {
        let envp = self.capture_env();

        if self.saw_nul() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "nul byte found in provided data",
            ));
        }

        let (ours, theirs) = self.setup_io(default, needs_stdin)?;

        let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? };

        Ok((Process { handle: Handle::new(process_handle) }, ours))
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        if self.saw_nul() {
            return io::Error::new(io::ErrorKind::InvalidInput, "nul byte found in provided data");
        }

        match self.setup_io(default, true) {
            Ok((_, _)) => {
                // FIXME: This is tough because we don't support the exec syscalls
                unimplemented!();
            }
            Err(e) => e,
        }
    }

    unsafe fn do_exec(
        &mut self,
        stdio: ChildPipes,
        maybe_envp: Option<&CStringArray>,
    ) -> io::Result<zx_handle_t> {
        use crate::sys::process::zircon::*;

        let envp = match maybe_envp {
            // None means to clone the current environment, which is done in the
            // flags below.
            None => ptr::null(),
            Some(envp) => envp.as_ptr(),
        };

        let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> {
            if let Some(local_fd) = local_io.fd() {
                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd,
                    target_fd,
                    ..Default::default()
                })
            } else {
                if let ChildStdio::Null = local_io {
                    // acts as no-op
                    return Ok(Default::default());
                }

                let mut handle = ZX_HANDLE_INVALID;
                let status = fdio_fd_clone(target_fd, &mut handle);
                if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED {
                    // This descriptor is closed; skip it rather than generating an
                    // error.
                    return Ok(Default::default());
                }
                zx_cvt(status)?;

                let mut cloned_fd = 0;
                zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?;

                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd: cloned_fd as i32,
                    target_fd,
                    ..Default::default()
                })
            }
        };

        // Clone stdin, stdout, and stderr
        let action1 = make_action(&stdio.stdin, 0)?;
        let action2 = make_action(&stdio.stdout, 1)?;
        let action3 = make_action(&stdio.stderr, 2)?;
        let actions = [action1, action2, action3];

        // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
        // always consumes transferred file descriptors.
        mem::forget(stdio);

        for callback in self.get_closures().iter_mut() {
            callback()?;
        }

        let mut process_handle: zx_handle_t = 0;
        zx_cvt(fdio_spawn_etc(
            ZX_HANDLE_INVALID,
            FDIO_SPAWN_CLONE_JOB
                | FDIO_SPAWN_CLONE_LDSVC
                | FDIO_SPAWN_CLONE_NAMESPACE
                | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
                | FDIO_SPAWN_CLONE_UTC_CLOCK,
            self.get_program_cstr().as_ptr(),
            self.get_argv().as_ptr(),
            envp,
            actions.len() as size_t,
            actions.as_ptr(),
            &mut process_handle,
            ptr::null_mut(),
        ))?;
        // FIXME: See if we want to do something with that err_msg

        Ok(process_handle)
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

pub struct Process {
    handle: Handle,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.handle.raw() as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        use crate::sys::process::zircon::*;

        unsafe {
            zx_cvt(zx_task_kill(self.handle.raw()))?;
        }

        Ok(())
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            zx_cvt(zx_object_wait_one(
                self.handle.raw(),
                ZX_TASK_TERMINATED,
                ZX_TIME_INFINITE,
                ptr::null_mut(),
            ))?;
            zx_cvt(zx_object_get_info(
                self.handle.raw(),
                ZX_INFO_PROCESS,
                &mut proc_info as *mut _ as *mut libc::c_void,
                mem::size_of::<zx_info_process_t>(),
                &mut actual,
                &mut avail,
            ))?;
        }
        if actual != 1 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Failed to get exit status of process",
            ));
        }
        Ok(ExitStatus(proc_info.return_code))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            let status =
                zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, 0, ptr::null_mut());
            match status {
                0 => {} // Success
                x if x == ERR_TIMED_OUT => {
                    return Ok(None);
                }
                _ => {
                    panic!("Failed to wait on process handle: {}", status);
                }
            }
            zx_cvt(zx_object_get_info(
                self.handle.raw(),
                ZX_INFO_PROCESS,
                &mut proc_info as *mut _ as *mut libc::c_void,
                mem::size_of::<zx_info_process_t>(),
                &mut actual,
                &mut avail,
            ))?;
        }
        if actual != 1 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Failed to get exit status of process",
            ));
        }
        Ok(Some(ExitStatus(proc_info.return_code)))
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(i64);

impl ExitStatus {
    pub fn success(&self) -> bool {
        self.code() == Some(0)
    }

    pub fn code(&self) -> Option<i32> {
        // FIXME: support extracting return code as an i64
        self.0.try_into().ok()
    }

    pub fn signal(&self) -> Option<i32> {
        None
    }

    // FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al.
    // I infer from the implementation of `success`, `code` and `signal` above that these are not
    // available on Fuchsia.
    //
    // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
    // other things from std::os::unix) properly.  This veneer is always going to be a bdoge.  So
    // while I don't know if these implementations are actually correct, I think they will do for
    // now at least.
    pub fn core_dumped(&self) -> bool {
        false
    }
    pub fn stopped_signal(&self) -> Option<i32> {
        None
    }
    pub fn continued(&self) -> bool {
        false
    }

    pub fn into_raw(&self) -> c_int {
        // We don't know what someone who calls into_raw() will do with this value, but it should
        // have the conventional Unix representation.  Despite the fact that this is not
        // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
        // same way.  (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
        // Unix.)
        //
        // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
        // do their own shifting and masking, or even pass the status to another computer running a
        // different Unix variant.
        //
        // The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
        // will give a raw Fuchsia status (whatever that is - I don't know, personally).  That is
        // not possible here becaause we must return a c_int because that's what Unix (including
        // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
        // necessarily fit.
        //
        // It seems to me that that the right answer would be to provide std::os::fuchsia with its
        // own ExitStatusExt, rather that trying to provide a not very convincing imitation of
        // Unix.  Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia.  But
        // fixing this up that is beyond the scope of my efforts now.
        let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to covert the value into a traditional Unix-style wait status, which cannot represent values greater than 255.");
        let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8;
        wait_status_as_if_unix
    }
}

/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
impl From<c_int> for ExitStatus {
    fn from(a: c_int) -> ExitStatus {
        ExitStatus(a as i64)
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "exit code: {}", self.0)
    }
}
<|endoftext|>


<commit_before><commit_msg>Nicer public items<commit_after><|endoftext|>


<commit_before><commit_msg>Fix warning on unused to_tokens_call<commit_after><|endoftext|>


<commit_before><commit_msg>Minor refactoring for selecting an element<commit_after><|endoftext|>


<commit_before><commit_msg>hmac md5<commit_after><|endoftext|>


<commit_before><commit_msg>Simplify data-handling logic.<commit_after><|endoftext|>


<commit_before><commit_msg>Don't escape tabs and spaces<commit_after><|endoftext|>


<commit_before>#![allow(deprecated)] // for SipHasher

use std::collections::hash_map::{Entry, HashMap};
use std::env;
use std::hash::{Hash, Hasher, SipHasher};
use std::path::{Path, PathBuf};
use std::process::Stdio;
use std::sync::Mutex;

use log::{debug, info, warn};
use serde::{Deserialize, Serialize};

use crate::util::paths;
use crate::util::{self, internal, profile, CargoResult, ProcessBuilder};

/// Information on the `rustc` executable
#[derive(Debug)]
pub struct Rustc {
    /// The location of the exe
    pub path: PathBuf,
    /// An optional program that will be passed the path of the rust exe as its first argument, and
    /// rustc args following this.
    pub wrapper: Option<ProcessBuilder>,
    /// Verbose version information (the output of `rustc -vV`)
    pub verbose_version: String,
    /// The host triple (arch-platform-OS), this comes from verbose_version.
    pub host: String,
    cache: Mutex<Cache>,
}

impl Rustc {
    /// Runs the compiler at `path` to learn various pieces of information about
    /// it, with an optional wrapper.
    ///
    /// If successful this function returns a description of the compiler along
    /// with a list of its capabilities.
    pub fn new(
        path: PathBuf,
        wrapper: Option<PathBuf>,
        rustup_rustc: &Path,
        cache_location: Option<PathBuf>,
    ) -> CargoResult<Rustc> {
        let _p = profile::start("Rustc::new");

        let mut cache = Cache::load(&path, rustup_rustc, cache_location);

        let mut cmd = util::process(&path);
        cmd.arg("-vV");
        let verbose_version = cache.cached_output(&cmd)?.0;

        let host = {
            let triple = verbose_version
                .lines()
                .find(|l| l.starts_with("host: "))
                .map(|l| &l[6..])
                .ok_or_else(|| internal("rustc -v didn't have a line for `host:`"))?;
            triple.to_string()
        };

        Ok(Rustc {
            path,
            wrapper: wrapper.map(util::process),
            verbose_version,
            host,
            cache: Mutex::new(cache),
        })
    }

    /// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`.
    pub fn process(&self) -> ProcessBuilder {
        match self.wrapper {
            Some(ref wrapper) if !wrapper.get_program().is_empty() => {
                let mut cmd = wrapper.clone();
                cmd.arg(&self.path);
                cmd
            }
            _ => self.process_no_wrapper(),
        }
    }

    pub fn process_no_wrapper(&self) -> ProcessBuilder {
        util::process(&self.path)
    }

    pub fn cached_output(&self, cmd: &ProcessBuilder) -> CargoResult<(String, String)> {
        self.cache.lock().unwrap().cached_output(cmd)
    }

    pub fn cached_success(&self, cmd: &ProcessBuilder) -> CargoResult<bool> {
        self.cache.lock().unwrap().cached_success(cmd)
    }

    pub fn set_wrapper(&mut self, wrapper: ProcessBuilder) {
        self.wrapper = Some(wrapper);
    }
}

/// It is a well known that `rustc` is not the fastest compiler in the world.
/// What is less known is that even `rustc --version --verbose` takes about a
/// hundred milliseconds! Because we need compiler version info even for no-op
/// builds, we cache it here, based on compiler's mtime and rustup's current
/// toolchain.
///
/// https://github.com/rust-lang/cargo/issues/5315
/// https://github.com/rust-lang/rust/issues/49761
#[derive(Debug)]
struct Cache {
    cache_location: Option<PathBuf>,
    dirty: bool,
    data: CacheData,
}

#[derive(Serialize, Deserialize, Debug, Default)]
struct CacheData {
    rustc_fingerprint: u64,
    outputs: HashMap<u64, (String, String)>,
    successes: HashMap<u64, bool>,
}

impl Cache {
    fn load(rustc: &Path, rustup_rustc: &Path, cache_location: Option<PathBuf>) -> Cache {
        match (cache_location, rustc_fingerprint(rustc, rustup_rustc)) {
            (Some(cache_location), Ok(rustc_fingerprint)) => {
                let empty = CacheData {
                    rustc_fingerprint,
                    outputs: HashMap::new(),
                    successes: HashMap::new(),
                };
                let mut dirty = true;
                let data = match read(&cache_location) {
                    Ok(data) => {
                        if data.rustc_fingerprint == rustc_fingerprint {
                            info!("reusing existing rustc info cache");
                            dirty = false;
                            data
                        } else {
                            info!("different compiler, creating new rustc info cache");
                            empty
                        }
                    }
                    Err(e) => {
                        info!("failed to read rustc info cache: {}", e);
                        empty
                    }
                };
                return Cache {
                    cache_location: Some(cache_location),
                    dirty,
                    data,
                };

                fn read(path: &Path) -> CargoResult<CacheData> {
                    let json = paths::read(path)?;
                    Ok(serde_json::from_str(&json)?)
                }
            }
            (_, fingerprint) => {
                if let Err(e) = fingerprint {
                    warn!("failed to calculate rustc fingerprint: {}", e);
                }
                info!("rustc info cache disabled");
                Cache {
                    cache_location: None,
                    dirty: false,
                    data: CacheData::default(),
                }
            }
        }
    }

    fn cached_output(&mut self, cmd: &ProcessBuilder) -> CargoResult<(String, String)> {
        let key = process_fingerprint(cmd);
        match self.data.outputs.entry(key) {
            Entry::Occupied(entry) => {
                info!("rustc info cache hit");
                Ok(entry.get().clone())
            }
            Entry::Vacant(entry) => {
                info!("rustc info cache miss");
                let output = cmd.exec_with_output()?;
                let stdout = String::from_utf8(output.stdout)
                    .map_err(|_| internal("rustc didn't return utf8 output"))?;
                let stderr = String::from_utf8(output.stderr)
                    .map_err(|_| internal("rustc didn't return utf8 output"))?;
                let output = (stdout, stderr);
                entry.insert(output.clone());
                self.dirty = true;
                Ok(output)
            }
        }
    }

    fn cached_success(&mut self, cmd: &ProcessBuilder) -> CargoResult<bool> {
        let key = process_fingerprint(cmd);
        match self.data.successes.entry(key) {
            Entry::Occupied(entry) => {
                info!("rustc info cache hit");
                Ok(*entry.get())
            }
            Entry::Vacant(entry) => {
                info!("rustc info cache miss");
                let success = cmd
                    .build_command()
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .status()?
                    .success();
                entry.insert(success);
                self.dirty = true;
                Ok(success)
            }
        }
    }
}

impl Drop for Cache {
    fn drop(&mut self) {
        if !self.dirty {
            return;
        }
        if let Some(ref path) = self.cache_location {
            let json = serde_json::to_string(&self.data).unwrap();
            match paths::write(path, json.as_bytes()) {
                Ok(()) => info!("updated rustc info cache"),
                Err(e) => warn!("failed to update rustc info cache: {}", e),
            }
        }
    }
}

fn rustc_fingerprint(path: &Path, rustup_rustc: &Path) -> CargoResult<u64> {
    let mut hasher = SipHasher::new_with_keys(0, 0);

    let path = paths::resolve_executable(path)?;
    path.hash(&mut hasher);

    paths::mtime(&path)?.hash(&mut hasher);

    // Rustup can change the effective compiler without touching
    // the `rustc` binary, so we try to account for this here.
    // If we see rustup's env vars, we mix them into the fingerprint,
    // but we also mix in the mtime of the actual compiler (and not
    // the rustup shim at `~/.cargo/bin/rustup`), because `RUSTUP_TOOLCHAIN`
    // could be just `stable-x86_64-unknown-linux-gnu`, i.e, it could
    // not mention the version of Rust at all, which changes after
    // `rustup update`.
    //
    // If we don't see rustup env vars, but it looks like the compiler
    // is managed by rustup, we conservatively bail out.
    let maybe_rustup = rustup_rustc == path;
    match (
        maybe_rustup,
        env::var("RUSTUP_HOME"),
        env::var("RUSTUP_TOOLCHAIN"),
    ) {
        (_, Ok(rustup_home), Ok(rustup_toolchain)) => {
            debug!("adding rustup info to rustc fingerprint");
            rustup_toolchain.hash(&mut hasher);
            rustup_home.hash(&mut hasher);
            let real_rustc = Path::new(&rustup_home)
                .join("toolchains")
                .join(rustup_toolchain)
                .join("bin")
                .join("rustc")
                .with_extension(env::consts::EXE_EXTENSION);
            paths::mtime(&real_rustc)?.hash(&mut hasher);
        }
        (true, _, _) => failure::bail!("probably rustup rustc, but without rustup's env vars"),
        _ => (),
    }

    Ok(hasher.finish())
}

fn process_fingerprint(cmd: &ProcessBuilder) -> u64 {
    let mut hasher = SipHasher::new_with_keys(0, 0);
    cmd.get_args().hash(&mut hasher);
    let mut env = cmd.get_envs().iter().collect::<Vec<_>>();
    env.sort_unstable();
    env.hash(&mut hasher);
    hasher.finish()
}
<commit_msg>Auto merge of #6879 - froydnj:patch-1, r=ehuss<commit_after>#![allow(deprecated)] // for SipHasher

use std::collections::hash_map::{Entry, HashMap};
use std::env;
use std::hash::{Hash, Hasher, SipHasher};
use std::path::{Path, PathBuf};
use std::process::Stdio;
use std::sync::Mutex;

use log::{debug, info, warn};
use serde::{Deserialize, Serialize};

use crate::util::paths;
use crate::util::{self, internal, profile, CargoResult, ProcessBuilder};

/// Information on the `rustc` executable
#[derive(Debug)]
pub struct Rustc {
    /// The location of the exe
    pub path: PathBuf,
    /// An optional program that will be passed the path of the rust exe as its first argument, and
    /// rustc args following this.
    pub wrapper: Option<ProcessBuilder>,
    /// Verbose version information (the output of `rustc -vV`)
    pub verbose_version: String,
    /// The host triple (arch-platform-OS), this comes from verbose_version.
    pub host: String,
    cache: Mutex<Cache>,
}

impl Rustc {
    /// Runs the compiler at `path` to learn various pieces of information about
    /// it, with an optional wrapper.
    ///
    /// If successful this function returns a description of the compiler along
    /// with a list of its capabilities.
    pub fn new(
        path: PathBuf,
        wrapper: Option<PathBuf>,
        rustup_rustc: &Path,
        cache_location: Option<PathBuf>,
    ) -> CargoResult<Rustc> {
        let _p = profile::start("Rustc::new");

        let mut cache = Cache::load(&path, rustup_rustc, cache_location);

        let mut cmd = util::process(&path);
        cmd.arg("-vV");
        let verbose_version = cache.cached_output(&cmd)?.0;

        let host = {
            let triple = verbose_version
                .lines()
                .find(|l| l.starts_with("host: "))
                .map(|l| &l[6..])
                .ok_or_else(|| internal("rustc -v didn't have a line for `host:`"))?;
            triple.to_string()
        };

        Ok(Rustc {
            path,
            wrapper: wrapper.map(util::process),
            verbose_version,
            host,
            cache: Mutex::new(cache),
        })
    }

    /// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`.
    pub fn process(&self) -> ProcessBuilder {
        match self.wrapper {
            Some(ref wrapper) if !wrapper.get_program().is_empty() => {
                let mut cmd = wrapper.clone();
                cmd.arg(&self.path);
                cmd
            }
            _ => self.process_no_wrapper(),
        }
    }

    pub fn process_no_wrapper(&self) -> ProcessBuilder {
        util::process(&self.path)
    }

    pub fn cached_output(&self, cmd: &ProcessBuilder) -> CargoResult<(String, String)> {
        self.cache.lock().unwrap().cached_output(cmd)
    }

    pub fn cached_success(&self, cmd: &ProcessBuilder) -> CargoResult<bool> {
        self.cache.lock().unwrap().cached_success(cmd)
    }

    pub fn set_wrapper(&mut self, wrapper: ProcessBuilder) {
        self.wrapper = Some(wrapper);
    }
}

/// It is a well known fact that `rustc` is not the fastest compiler in the
/// world.  What is less known is that even `rustc --version --verbose` takes
/// about a hundred milliseconds! Because we need compiler version info even
/// for no-op builds, we cache it here, based on compiler's mtime and rustup's
/// current toolchain.
///
/// https://github.com/rust-lang/cargo/issues/5315
/// https://github.com/rust-lang/rust/issues/49761
#[derive(Debug)]
struct Cache {
    cache_location: Option<PathBuf>,
    dirty: bool,
    data: CacheData,
}

#[derive(Serialize, Deserialize, Debug, Default)]
struct CacheData {
    rustc_fingerprint: u64,
    outputs: HashMap<u64, (String, String)>,
    successes: HashMap<u64, bool>,
}

impl Cache {
    fn load(rustc: &Path, rustup_rustc: &Path, cache_location: Option<PathBuf>) -> Cache {
        match (cache_location, rustc_fingerprint(rustc, rustup_rustc)) {
            (Some(cache_location), Ok(rustc_fingerprint)) => {
                let empty = CacheData {
                    rustc_fingerprint,
                    outputs: HashMap::new(),
                    successes: HashMap::new(),
                };
                let mut dirty = true;
                let data = match read(&cache_location) {
                    Ok(data) => {
                        if data.rustc_fingerprint == rustc_fingerprint {
                            info!("reusing existing rustc info cache");
                            dirty = false;
                            data
                        } else {
                            info!("different compiler, creating new rustc info cache");
                            empty
                        }
                    }
                    Err(e) => {
                        info!("failed to read rustc info cache: {}", e);
                        empty
                    }
                };
                return Cache {
                    cache_location: Some(cache_location),
                    dirty,
                    data,
                };

                fn read(path: &Path) -> CargoResult<CacheData> {
                    let json = paths::read(path)?;
                    Ok(serde_json::from_str(&json)?)
                }
            }
            (_, fingerprint) => {
                if let Err(e) = fingerprint {
                    warn!("failed to calculate rustc fingerprint: {}", e);
                }
                info!("rustc info cache disabled");
                Cache {
                    cache_location: None,
                    dirty: false,
                    data: CacheData::default(),
                }
            }
        }
    }

    fn cached_output(&mut self, cmd: &ProcessBuilder) -> CargoResult<(String, String)> {
        let key = process_fingerprint(cmd);
        match self.data.outputs.entry(key) {
            Entry::Occupied(entry) => {
                info!("rustc info cache hit");
                Ok(entry.get().clone())
            }
            Entry::Vacant(entry) => {
                info!("rustc info cache miss");
                let output = cmd.exec_with_output()?;
                let stdout = String::from_utf8(output.stdout)
                    .map_err(|_| internal("rustc didn't return utf8 output"))?;
                let stderr = String::from_utf8(output.stderr)
                    .map_err(|_| internal("rustc didn't return utf8 output"))?;
                let output = (stdout, stderr);
                entry.insert(output.clone());
                self.dirty = true;
                Ok(output)
            }
        }
    }

    fn cached_success(&mut self, cmd: &ProcessBuilder) -> CargoResult<bool> {
        let key = process_fingerprint(cmd);
        match self.data.successes.entry(key) {
            Entry::Occupied(entry) => {
                info!("rustc info cache hit");
                Ok(*entry.get())
            }
            Entry::Vacant(entry) => {
                info!("rustc info cache miss");
                let success = cmd
                    .build_command()
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .status()?
                    .success();
                entry.insert(success);
                self.dirty = true;
                Ok(success)
            }
        }
    }
}

impl Drop for Cache {
    fn drop(&mut self) {
        if !self.dirty {
            return;
        }
        if let Some(ref path) = self.cache_location {
            let json = serde_json::to_string(&self.data).unwrap();
            match paths::write(path, json.as_bytes()) {
                Ok(()) => info!("updated rustc info cache"),
                Err(e) => warn!("failed to update rustc info cache: {}", e),
            }
        }
    }
}

fn rustc_fingerprint(path: &Path, rustup_rustc: &Path) -> CargoResult<u64> {
    let mut hasher = SipHasher::new_with_keys(0, 0);

    let path = paths::resolve_executable(path)?;
    path.hash(&mut hasher);

    paths::mtime(&path)?.hash(&mut hasher);

    // Rustup can change the effective compiler without touching
    // the `rustc` binary, so we try to account for this here.
    // If we see rustup's env vars, we mix them into the fingerprint,
    // but we also mix in the mtime of the actual compiler (and not
    // the rustup shim at `~/.cargo/bin/rustup`), because `RUSTUP_TOOLCHAIN`
    // could be just `stable-x86_64-unknown-linux-gnu`, i.e, it could
    // not mention the version of Rust at all, which changes after
    // `rustup update`.
    //
    // If we don't see rustup env vars, but it looks like the compiler
    // is managed by rustup, we conservatively bail out.
    let maybe_rustup = rustup_rustc == path;
    match (
        maybe_rustup,
        env::var("RUSTUP_HOME"),
        env::var("RUSTUP_TOOLCHAIN"),
    ) {
        (_, Ok(rustup_home), Ok(rustup_toolchain)) => {
            debug!("adding rustup info to rustc fingerprint");
            rustup_toolchain.hash(&mut hasher);
            rustup_home.hash(&mut hasher);
            let real_rustc = Path::new(&rustup_home)
                .join("toolchains")
                .join(rustup_toolchain)
                .join("bin")
                .join("rustc")
                .with_extension(env::consts::EXE_EXTENSION);
            paths::mtime(&real_rustc)?.hash(&mut hasher);
        }
        (true, _, _) => failure::bail!("probably rustup rustc, but without rustup's env vars"),
        _ => (),
    }

    Ok(hasher.finish())
}

fn process_fingerprint(cmd: &ProcessBuilder) -> u64 {
    let mut hasher = SipHasher::new_with_keys(0, 0);
    cmd.get_args().hash(&mut hasher);
    let mut env = cmd.get_envs().iter().collect::<Vec<_>>();
    env.sort_unstable();
    env.hash(&mut hasher);
    hasher.finish()
}
<|endoftext|>