<commit_before>//!
//!
//! TODO: document me

use bindings::*;
use std::slice::bytes::copy_memory;

/// Number of bytes in the sign public key
pub static PUBKEY_BYTES: uint = 32;
/// Number of bytes in the sign private key
pub static SECKEY_BYTES: uint = 64;
/// Bytes of padding used in each signed message
pub static SIGN_BYTES: uint = 64;

pub struct PublicKey ([u8, ..PUBKEY_BYTES]);
pub struct SecretKey ([u8, ..SECKEY_BYTES]);

/// Encapsulates the verification key and signed message.
pub struct SignedMsg {
    pub pk: PublicKey,
    pub signed: Vec<u8>
}

impl SignedMsg {
    /// Verify the validity of a given signed message against this public key.
    pub fn verify(&self) -> Option<Vec<u8>> {
        let PublicKey(pk) = self.pk;

        let mut msg: Vec<u8> = Vec::from_elem(self.signed.len(), 0u8);
        let mut msg_len: u64 = 0;

        unsafe {
            match crypto_sign_open(msg.as_mut_ptr(),
                                   &mut msg_len,
                                   self.signed.as_ptr(),
                                   self.signed.len() as u64,
                                   pk.as_ptr()) {
                -3 => None,
                0  => {
                    msg.set_len(msg_len as uint);
                    Some(msg)
                },
                _  => fail!("Impossible things happened")
            }
        }
    }

    pub fn from_bytes(msg: &[u8]) -> Option<SignedMsg> {
        if msg.len() < PUBKEY_BYTES + SIGN_BYTES {
            return None;
        }

        let mut pk = [0u8, ..PUBKEY_BYTES];
        let signed = msg.slice_from(PUBKEY_BYTES);

        copy_memory(pk, msg.slice(0, PUBKEY_BYTES));

        Some(SignedMsg { pk: PublicKey(pk), signed: Vec::from_slice(signed) })

    }

    pub fn as_bytes(&self) -> Vec<u8> {
        let PublicKey(pk) = self.pk;
        let mut buf = Vec::from_slice(pk);

        buf.push_all(self.signed.as_slice());

        buf
    }
}

/// Matching secret / public keys.
pub struct Keypair {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl Keypair {
    /// Securely generate a random new signing keypair
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBKEY_BYTES];
        let mut sk = [0u8, ..SECKEY_BYTES];

        unsafe {
            crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        }

        Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
    }

    /// Sign a given message with this keypair's secret key.
    pub fn sign(&self, msg: &[u8]) -> SignedMsg {
        let mut signed: Vec<u8> = Vec::from_elem(msg.len() + SIGN_BYTES, 0u8);
        let mut signed_len: u64 = 0;

        let SecretKey(sk) = self.sk;

        unsafe {
            crypto_sign(signed.as_mut_ptr(),
                        &mut signed_len,
                        msg.as_ptr(),
                        msg.len() as u64,
                        sk.as_ptr());

            signed.set_len(signed_len as uint);
        }

        SignedMsg { pk: self.pk, signed: signed }
    }
}

#[test]
fn test_sign_sanity() {
    for i in range(1 as uint, 16) {
        let keypair = Keypair::new();
        let msg = Vec::from_elem(i * 4, i as u8);

        let SecretKey(sk) = keypair.sk;
        let PublicKey(pk) = keypair.pk;

        println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

        let sig = keypair.sign(msg.as_slice());
        let desig = sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

        assert!(desig.is_some());
        assert!(desig.unwrap() == msg);
    }
}

#[test]
fn test_sign_fail_sanity() {
    let key1 = Keypair::new();
    let key2 = Keypair::new();

    let msg = b"some message";

    let sig = key1.sign(msg);

    let altered_sig = SignedMsg { pk: key2.pk, signed: sig.signed.clone() };
    let desig = altered_sig.verify();

    println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

    assert!(desig.is_none());
}
<commit_msg>Add sign usage<commit_after>//!
//! ## Usage
//!
//! ```rust{.example}
//! use tweetnacl::sign::Keypair;
//!
//! let key = Keypair::new();
//! let msg = b"some important message";
//!
//! let signed = key.sign(msg);
//!
//! // ...
//!
//! let plain_opt = signed.verify();
//! assert!(plain_opt.is_some());
//! assert!(plain_opt.unwrap().as_slice() == msg);
//! ```
//!
//! TODO: document me

use bindings::*;
use std::slice::bytes::copy_memory;

/// Number of bytes in the sign public key
pub static PUBKEY_BYTES: uint = 32;
/// Number of bytes in the sign private key
pub static SECKEY_BYTES: uint = 64;
/// Bytes of padding used in each signed message
pub static SIGN_BYTES: uint = 64;

pub struct PublicKey ([u8, ..PUBKEY_BYTES]);
pub struct SecretKey ([u8, ..SECKEY_BYTES]);

/// Encapsulates the verification key and signed message.
pub struct SignedMsg {
    pub pk: PublicKey,
    pub signed: Vec<u8>
}

impl SignedMsg {
    /// Verify the validity of a given signed message against this public key.
    pub fn verify(&self) -> Option<Vec<u8>> {
        let PublicKey(pk) = self.pk;

        let mut msg: Vec<u8> = Vec::from_elem(self.signed.len(), 0u8);
        let mut msg_len: u64 = 0;

        unsafe {
            match crypto_sign_open(msg.as_mut_ptr(),
                                   &mut msg_len,
                                   self.signed.as_ptr(),
                                   self.signed.len() as u64,
                                   pk.as_ptr()) {
                -3 => None,
                0  => {
                    msg.set_len(msg_len as uint);
                    Some(msg)
                },
                _  => fail!("Impossible things happened")
            }
        }
    }

    pub fn from_bytes(msg: &[u8]) -> Option<SignedMsg> {
        if msg.len() < PUBKEY_BYTES + SIGN_BYTES {
            return None;
        }

        let mut pk = [0u8, ..PUBKEY_BYTES];
        let signed = msg.slice_from(PUBKEY_BYTES);

        copy_memory(pk, msg.slice(0, PUBKEY_BYTES));

        Some(SignedMsg { pk: PublicKey(pk), signed: Vec::from_slice(signed) })

    }

    pub fn as_bytes(&self) -> Vec<u8> {
        let PublicKey(pk) = self.pk;
        let mut buf = Vec::from_slice(pk);

        buf.push_all(self.signed.as_slice());

        buf
    }
}

/// Matching secret / public keys.
pub struct Keypair {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl Keypair {
    /// Securely generate a random new signing keypair
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBKEY_BYTES];
        let mut sk = [0u8, ..SECKEY_BYTES];

        unsafe {
            crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        }

        Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
    }

    /// Sign a given message with this keypair's secret key.
    pub fn sign(&self, msg: &[u8]) -> SignedMsg {
        let mut signed: Vec<u8> = Vec::from_elem(msg.len() + SIGN_BYTES, 0u8);
        let mut signed_len: u64 = 0;

        let SecretKey(sk) = self.sk;

        unsafe {
            crypto_sign(signed.as_mut_ptr(),
                        &mut signed_len,
                        msg.as_ptr(),
                        msg.len() as u64,
                        sk.as_ptr());

            signed.set_len(signed_len as uint);
        }

        SignedMsg { pk: self.pk, signed: signed }
    }
}

#[test]
fn test_sign_sanity() {
    for i in range(1 as uint, 16) {
        let keypair = Keypair::new();
        let msg = Vec::from_elem(i * 4, i as u8);

        let SecretKey(sk) = keypair.sk;
        let PublicKey(pk) = keypair.pk;

        println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

        let sig = keypair.sign(msg.as_slice());
        let desig = sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

        assert!(desig.is_some());
        assert!(desig.unwrap() == msg);
    }
}

#[test]
fn test_sign_fail_sanity() {
    let key1 = Keypair::new();
    let key2 = Keypair::new();

    let msg = b"some message";

    let sig = key1.sign(msg);

    let altered_sig = SignedMsg { pk: key2.pk, signed: sig.signed.clone() };
    let desig = altered_sig.verify();

    println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

    assert!(desig.is_none());
}
<|endoftext|>


<commit_before>//!
//!
//! TODO: document me

use bindings::*;

/// Number of bytes in the sign public key
pub static PUBKEY_BYTES: uint = 32;
/// Number of bytes in the sign private key
pub static SECKEY_BYTES: uint = 64;
/// Bytes of padding used in each signed message
pub static SIGN_BYTES: uint = 64;

pub struct PublicKey ([u8, ..PUBKEY_BYTES]);
pub struct SecretKey ([u8, ..SECKEY_BYTES]);

/// Encapsulates the verification key and signed message.
pub struct SignedMsg {
    pub pk: PublicKey,
    pub signed: Vec<u8>
}

impl SignedMsg {
    /// Verify the validity of a given signed message against this public key.
    pub fn verify(&self) -> Option<Vec<u8>> {
        let PublicKey(pk) = self.pk;

        let mut msg: Vec<u8> = Vec::from_elem(self.signed.len(), 0u8);
        let mut msg_len: u64 = 0;

        unsafe {
            match crypto_sign_open(msg.as_mut_ptr(),
                                   &mut msg_len,
                                   self.signed.as_ptr(),
                                   self.signed.len() as u64,
                                   pk.as_ptr()) {
                -3 => None,
                0  => {
                    msg.set_len(msg_len as uint);
                    Some(msg)
                },
                _  => fail!("Impossible things happened")
            }
        }
    }
}

/// Matching secret / public keys.
pub struct Keypair {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl Keypair {
    /// Securely generate a random new signing keypair
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBKEY_BYTES];
        let mut sk = [0u8, ..SECKEY_BYTES];

        unsafe {
            crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        }

        Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
    }

    /// Sign a given message with this keypair's secret key.
    pub fn sign(&self, msg: &[u8]) -> SignedMsg {
        let mut signed: Vec<u8> = Vec::from_elem(msg.len() + SIGN_BYTES, 0u8);
        let mut signed_len: u64 = 0;

        let SecretKey(sk) = self.sk;

        unsafe {
            crypto_sign(signed.as_mut_ptr(),
                        &mut signed_len,
                        msg.as_ptr(),
                        msg.len() as u64,
                        sk.as_ptr());

            signed.set_len(signed_len as uint);
        }

        SignedMsg { pk: self.pk, signed: signed }
    }
}

#[test]
fn test_sign_sanity() {
    for i in range(1 as uint, 16) {
        let keypair = Keypair::new();
        let msg = Vec::from_elem(i * 4, i as u8);

        let SecretKey(sk) = keypair.sk;
        let PublicKey(pk) = keypair.pk;

        println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

        let sig = keypair.sign(msg.as_slice());
        let desig = sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

        assert!(desig.is_some());
        assert!(desig.unwrap() == msg);
    }
}

#[test]
fn test_sign_fail_sanity() {
    let key1 = Keypair::new();
    let key2 = Keypair::new();

    let msg = b"some message";

    let sig = key1.sign(msg);

    let altered_sig = SignedMsg { pk: key2.pk, signed: sig.signed.clone() };
    let desig = altered_sig.verify();

    println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

    assert!(desig.is_none());
}
<commit_msg>Add SignedMsg from_bytes/as_bytes<commit_after>//!
//!
//! TODO: document me

use bindings::*;
use std::slice::bytes::copy_memory;

/// Number of bytes in the sign public key
pub static PUBKEY_BYTES: uint = 32;
/// Number of bytes in the sign private key
pub static SECKEY_BYTES: uint = 64;
/// Bytes of padding used in each signed message
pub static SIGN_BYTES: uint = 64;

pub struct PublicKey ([u8, ..PUBKEY_BYTES]);
pub struct SecretKey ([u8, ..SECKEY_BYTES]);

/// Encapsulates the verification key and signed message.
pub struct SignedMsg {
    pub pk: PublicKey,
    pub signed: Vec<u8>
}

impl SignedMsg {
    /// Verify the validity of a given signed message against this public key.
    pub fn verify(&self) -> Option<Vec<u8>> {
        let PublicKey(pk) = self.pk;

        let mut msg: Vec<u8> = Vec::from_elem(self.signed.len(), 0u8);
        let mut msg_len: u64 = 0;

        unsafe {
            match crypto_sign_open(msg.as_mut_ptr(),
                                   &mut msg_len,
                                   self.signed.as_ptr(),
                                   self.signed.len() as u64,
                                   pk.as_ptr()) {
                -3 => None,
                0  => {
                    msg.set_len(msg_len as uint);
                    Some(msg)
                },
                _  => fail!("Impossible things happened")
            }
        }
    }

    pub fn from_bytes(msg: &[u8]) -> Option<SignedMsg> {
        if msg.len() < PUBKEY_BYTES + SIGN_BYTES {
            return None;
        }

        let mut pk = [0u8, ..PUBKEY_BYTES];
        let signed = msg.slice_from(PUBKEY_BYTES);

        copy_memory(pk, msg.slice(0, PUBKEY_BYTES));

        Some(SignedMsg { pk: PublicKey(pk), signed: Vec::from_slice(signed) })

    }

    pub fn as_bytes(&self) -> Vec<u8> {
        let PublicKey(pk) = self.pk;
        let mut buf = Vec::from_slice(pk);

        buf.push_all(self.signed.as_slice());

        buf
    }
}

/// Matching secret / public keys.
pub struct Keypair {
    pub sk: SecretKey,
    pub pk: PublicKey
}

impl Keypair {
    /// Securely generate a random new signing keypair
    pub fn new() -> Keypair {
        let mut pk = [0u8, ..PUBKEY_BYTES];
        let mut sk = [0u8, ..SECKEY_BYTES];

        unsafe {
            crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        }

        Keypair { pk: PublicKey(pk), sk: SecretKey(sk) }
    }

    /// Sign a given message with this keypair's secret key.
    pub fn sign(&self, msg: &[u8]) -> SignedMsg {
        let mut signed: Vec<u8> = Vec::from_elem(msg.len() + SIGN_BYTES, 0u8);
        let mut signed_len: u64 = 0;

        let SecretKey(sk) = self.sk;

        unsafe {
            crypto_sign(signed.as_mut_ptr(),
                        &mut signed_len,
                        msg.as_ptr(),
                        msg.len() as u64,
                        sk.as_ptr());

            signed.set_len(signed_len as uint);
        }

        SignedMsg { pk: self.pk, signed: signed }
    }
}

#[test]
fn test_sign_sanity() {
    for i in range(1 as uint, 16) {
        let keypair = Keypair::new();
        let msg = Vec::from_elem(i * 4, i as u8);

        let SecretKey(sk) = keypair.sk;
        let PublicKey(pk) = keypair.pk;

        println!("sk: {}\npk: {}", sk.as_slice(), pk.as_slice());

        let sig = keypair.sign(msg.as_slice());
        let desig = sig.verify();

        println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

        assert!(desig.is_some());
        assert!(desig.unwrap() == msg);
    }
}

#[test]
fn test_sign_fail_sanity() {
    let key1 = Keypair::new();
    let key2 = Keypair::new();

    let msg = b"some message";

    let sig = key1.sign(msg);

    let altered_sig = SignedMsg { pk: key2.pk, signed: sig.signed.clone() };
    let desig = altered_sig.verify();

    println!("msg:\t{}\nsig:\t{}\ndesig:\t{}", msg, sig.signed, desig);

    assert!(desig.is_none());
}
<|endoftext|>


<commit_before>use super::{Value, ValueRef};
use std::error::Error;
use std::fmt;

/// Enum listing possible errors from `FromSql` trait.
#[derive(Debug)]
pub enum FromSqlError {
    /// Error when an SQLite value is requested, but the type of the result
    /// cannot be converted to the requested Rust type.
    InvalidType,

    /// Error when the i64 value returned by SQLite cannot be stored into the
    /// requested type.
    OutOfRange(i64),

    /// Error returned when reading an `i128` from a blob with a size
    /// other than 16. Only available when the `i128_blob` feature is enabled.
    #[cfg(feature = "i128_blob")]
    InvalidI128Size(usize),

    /// Error returned when reading a `uuid` from a blob with a size
    /// other than 16. Only available when the `uuid` feature is enabled.
    #[cfg(feature = "uuid")]
    InvalidUuidSize(usize),

    /// An error case available for implementors of the `FromSql` trait.
    Other(Box<dyn Error + Send + Sync>),
}

impl PartialEq for FromSqlError {
    fn eq(&self, other: &FromSqlError) -> bool {
        match (self, other) {
            (FromSqlError::InvalidType, FromSqlError::InvalidType) => true,
            (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
            #[cfg(feature = "i128_blob")]
            (FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2,
            #[cfg(feature = "uuid")]
            (FromSqlError::InvalidUuidSize(s1), FromSqlError::InvalidUuidSize(s2)) => s1 == s2,
            (..) => false,
        }
    }
}

impl fmt::Display for FromSqlError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            FromSqlError::InvalidType => write!(f, "Invalid type"),
            FromSqlError::OutOfRange(i) => write!(f, "Value {} out of range", i),
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(s) => {
                write!(f, "Cannot read 128bit value out of {} byte blob", s)
            }
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(s) => {
                write!(f, "Cannot read UUID value out of {} byte blob", s)
            }
            FromSqlError::Other(ref err) => err.fmt(f),
        }
    }
}

impl Error for FromSqlError {
    fn description(&self) -> &str {
        match *self {
            FromSqlError::InvalidType => "invalid type",
            FromSqlError::OutOfRange(_) => "value out of range",
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(_) => "unexpected blob size for 128bit value",
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(_) => "unexpected blob size for UUID value",
            FromSqlError::Other(ref err) => err.description(),
        }
    }

    #[allow(clippy::match_same_arms)]
    #[allow(deprecated)]
    fn cause(&self) -> Option<&dyn Error> {
        match *self {
            FromSqlError::Other(ref err) => err.cause(),
            _ => None,
        }
    }
}

/// Result type for implementors of the `FromSql` trait.
pub type FromSqlResult<T> = Result<T, FromSqlError>;

/// A trait for types that can be created from a SQLite value.
///
/// Note that `FromSql` and `ToSql` are defined for most integral types, but
/// not `u64` or `usize`. This is intentional; SQLite returns integers as
/// signed 64-bit values, which cannot fully represent the range of these
/// types. Rusqlite would have to
/// decide how to handle negative values: return an error or reinterpret as a
/// very large postive numbers, neither of which
/// is guaranteed to be correct for everyone. Callers can work around this by
/// fetching values as i64 and then doing the interpretation themselves or by
/// defining a newtype and implementing `FromSql`/`ToSql` for it.
pub trait FromSql: Sized {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
}

impl FromSql for isize {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        i64::column_result(value).and_then(|i| {
            if i < isize::min_value() as i64 || i > isize::max_value() as i64 {
                Err(FromSqlError::OutOfRange(i))
            } else {
                Ok(i as isize)
            }
        })
    }
}

macro_rules! from_sql_integral(
    ($t:ident) => (
        impl FromSql for $t {
            fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
                i64::column_result(value).and_then(|i| {
                    if i < i64::from($t::min_value()) || i > i64::from($t::max_value()) {
                        Err(FromSqlError::OutOfRange(i))
                    } else {
                        Ok(i as $t)
                    }
                })
            }
        }
    )
);

from_sql_integral!(i8);
from_sql_integral!(i16);
from_sql_integral!(i32);
from_sql_integral!(u8);
from_sql_integral!(u16);
from_sql_integral!(u32);

impl FromSql for i64 {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_i64()
    }
}

impl FromSql for f64 {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Integer(i) => Ok(i as f64),
            ValueRef::Real(f) => Ok(f),
            _ => Err(FromSqlError::InvalidType),
        }
    }
}

impl FromSql for bool {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        i64::column_result(value).map(|i| match i {
            0 => false,
            _ => true,
        })
    }
}

impl FromSql for String {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(ToString::to_string)
    }
}

impl FromSql for Vec<u8> {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_blob().map(|b| b.to_vec())
    }
}

#[cfg(feature = "i128_blob")]
impl FromSql for i128 {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        use byteorder::{BigEndian, ByteOrder};

        value.as_blob().and_then(|bytes| {
            if bytes.len() == 16 {
                Ok(BigEndian::read_i128(bytes) ^ (1i128 << 127))
            } else {
                Err(FromSqlError::InvalidI128Size(bytes.len()))
            }
        })
    }
}

#[cfg(feature = "uuid")]
impl FromSql for uuid::Uuid {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value
            .as_blob()
            .and_then(|bytes| {
                uuid::Builder::from_slice(bytes)
                    .map_err(|_| FromSqlError::InvalidUuidSize(bytes.len()))
            })
            .map(|mut builder| builder.build())
    }
}

impl<T: FromSql> FromSql for Option<T> {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Null => Ok(None),
            _ => FromSql::column_result(value).map(Some),
        }
    }
}

impl FromSql for Value {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        Ok(value.into())
    }
}

#[cfg(test)]
mod test {
    use super::FromSql;
    use crate::{Connection, Error};

    fn checked_memory_handle() -> Connection {
        Connection::open_in_memory().unwrap()
    }

    #[test]
    fn test_integral_ranges() {
        let db = checked_memory_handle();

        fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
        where
            T: Into<i64> + FromSql + ::std::fmt::Debug,
        {
            for n in out_of_range {
                let err = db
                    .query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
                    .unwrap_err();
                match err {
                    Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
                    _ => panic!("unexpected error: {}", err),
                }
            }
            for n in in_range {
                assert_eq!(
                    *n,
                    db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
                        .unwrap()
                        .into()
                );
            }
        }

        check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]);
        check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]);
        check_ranges::<i32>(
            &db,
            &[-2_147_483_649, 2_147_483_648],
            &[-2_147_483_648, -1, 0, 1, 2_147_483_647],
        );
        check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
        check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
        check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
    }
}
<commit_msg>Add FromSql for Box<str>, Rc<str> and Arc<str><commit_after>use super::{Value, ValueRef};
use std::error::Error;
use std::fmt;

/// Enum listing possible errors from `FromSql` trait.
#[derive(Debug)]
pub enum FromSqlError {
    /// Error when an SQLite value is requested, but the type of the result
    /// cannot be converted to the requested Rust type.
    InvalidType,

    /// Error when the i64 value returned by SQLite cannot be stored into the
    /// requested type.
    OutOfRange(i64),

    /// Error returned when reading an `i128` from a blob with a size
    /// other than 16. Only available when the `i128_blob` feature is enabled.
    #[cfg(feature = "i128_blob")]
    InvalidI128Size(usize),

    /// Error returned when reading a `uuid` from a blob with a size
    /// other than 16. Only available when the `uuid` feature is enabled.
    #[cfg(feature = "uuid")]
    InvalidUuidSize(usize),

    /// An error case available for implementors of the `FromSql` trait.
    Other(Box<dyn Error + Send + Sync>),
}

impl PartialEq for FromSqlError {
    fn eq(&self, other: &FromSqlError) -> bool {
        match (self, other) {
            (FromSqlError::InvalidType, FromSqlError::InvalidType) => true,
            (FromSqlError::OutOfRange(n1), FromSqlError::OutOfRange(n2)) => n1 == n2,
            #[cfg(feature = "i128_blob")]
            (FromSqlError::InvalidI128Size(s1), FromSqlError::InvalidI128Size(s2)) => s1 == s2,
            #[cfg(feature = "uuid")]
            (FromSqlError::InvalidUuidSize(s1), FromSqlError::InvalidUuidSize(s2)) => s1 == s2,
            (..) => false,
        }
    }
}

impl fmt::Display for FromSqlError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            FromSqlError::InvalidType => write!(f, "Invalid type"),
            FromSqlError::OutOfRange(i) => write!(f, "Value {} out of range", i),
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(s) => {
                write!(f, "Cannot read 128bit value out of {} byte blob", s)
            }
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(s) => {
                write!(f, "Cannot read UUID value out of {} byte blob", s)
            }
            FromSqlError::Other(ref err) => err.fmt(f),
        }
    }
}

impl Error for FromSqlError {
    fn description(&self) -> &str {
        match *self {
            FromSqlError::InvalidType => "invalid type",
            FromSqlError::OutOfRange(_) => "value out of range",
            #[cfg(feature = "i128_blob")]
            FromSqlError::InvalidI128Size(_) => "unexpected blob size for 128bit value",
            #[cfg(feature = "uuid")]
            FromSqlError::InvalidUuidSize(_) => "unexpected blob size for UUID value",
            FromSqlError::Other(ref err) => err.description(),
        }
    }

    #[allow(clippy::match_same_arms)]
    #[allow(deprecated)]
    fn cause(&self) -> Option<&dyn Error> {
        match *self {
            FromSqlError::Other(ref err) => err.cause(),
            _ => None,
        }
    }
}

/// Result type for implementors of the `FromSql` trait.
pub type FromSqlResult<T> = Result<T, FromSqlError>;

/// A trait for types that can be created from a SQLite value.
///
/// Note that `FromSql` and `ToSql` are defined for most integral types, but
/// not `u64` or `usize`. This is intentional; SQLite returns integers as
/// signed 64-bit values, which cannot fully represent the range of these
/// types. Rusqlite would have to
/// decide how to handle negative values: return an error or reinterpret as a
/// very large postive numbers, neither of which
/// is guaranteed to be correct for everyone. Callers can work around this by
/// fetching values as i64 and then doing the interpretation themselves or by
/// defining a newtype and implementing `FromSql`/`ToSql` for it.
pub trait FromSql: Sized {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self>;
}

impl FromSql for isize {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        i64::column_result(value).and_then(|i| {
            if i < isize::min_value() as i64 || i > isize::max_value() as i64 {
                Err(FromSqlError::OutOfRange(i))
            } else {
                Ok(i as isize)
            }
        })
    }
}

macro_rules! from_sql_integral(
    ($t:ident) => (
        impl FromSql for $t {
            fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
                i64::column_result(value).and_then(|i| {
                    if i < i64::from($t::min_value()) || i > i64::from($t::max_value()) {
                        Err(FromSqlError::OutOfRange(i))
                    } else {
                        Ok(i as $t)
                    }
                })
            }
        }
    )
);

from_sql_integral!(i8);
from_sql_integral!(i16);
from_sql_integral!(i32);
from_sql_integral!(u8);
from_sql_integral!(u16);
from_sql_integral!(u32);

impl FromSql for i64 {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_i64()
    }
}

impl FromSql for f64 {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Integer(i) => Ok(i as f64),
            ValueRef::Real(f) => Ok(f),
            _ => Err(FromSqlError::InvalidType),
        }
    }
}

impl FromSql for bool {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        i64::column_result(value).map(|i| match i {
            0 => false,
            _ => true,
        })
    }
}

impl FromSql for String {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(ToString::to_string)
    }
}

impl FromSql for Box<str> {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for std::rc::Rc<str> {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for std::sync::Arc<str> {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_str().map(Into::into)
    }
}

impl FromSql for Vec<u8> {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value.as_blob().map(|b| b.to_vec())
    }
}

#[cfg(feature = "i128_blob")]
impl FromSql for i128 {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        use byteorder::{BigEndian, ByteOrder};

        value.as_blob().and_then(|bytes| {
            if bytes.len() == 16 {
                Ok(BigEndian::read_i128(bytes) ^ (1i128 << 127))
            } else {
                Err(FromSqlError::InvalidI128Size(bytes.len()))
            }
        })
    }
}

#[cfg(feature = "uuid")]
impl FromSql for uuid::Uuid {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        value
            .as_blob()
            .and_then(|bytes| {
                uuid::Builder::from_slice(bytes)
                    .map_err(|_| FromSqlError::InvalidUuidSize(bytes.len()))
            })
            .map(|mut builder| builder.build())
    }
}

impl<T: FromSql> FromSql for Option<T> {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value {
            ValueRef::Null => Ok(None),
            _ => FromSql::column_result(value).map(Some),
        }
    }
}

impl FromSql for Value {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        Ok(value.into())
    }
}

#[cfg(test)]
mod test {
    use super::FromSql;
    use crate::{Connection, Error};

    fn checked_memory_handle() -> Connection {
        Connection::open_in_memory().unwrap()
    }

    #[test]
    fn test_integral_ranges() {
        let db = checked_memory_handle();

        fn check_ranges<T>(db: &Connection, out_of_range: &[i64], in_range: &[i64])
        where
            T: Into<i64> + FromSql + ::std::fmt::Debug,
        {
            for n in out_of_range {
                let err = db
                    .query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
                    .unwrap_err();
                match err {
                    Error::IntegralValueOutOfRange(_, value) => assert_eq!(*n, value),
                    _ => panic!("unexpected error: {}", err),
                }
            }
            for n in in_range {
                assert_eq!(
                    *n,
                    db.query_row("SELECT ?", &[n], |r| r.get::<_, T>(0))
                        .unwrap()
                        .into()
                );
            }
        }

        check_ranges::<i8>(&db, &[-129, 128], &[-128, 0, 1, 127]);
        check_ranges::<i16>(&db, &[-32769, 32768], &[-32768, -1, 0, 1, 32767]);
        check_ranges::<i32>(
            &db,
            &[-2_147_483_649, 2_147_483_648],
            &[-2_147_483_648, -1, 0, 1, 2_147_483_647],
        );
        check_ranges::<u8>(&db, &[-2, -1, 256], &[0, 1, 255]);
        check_ranges::<u16>(&db, &[-2, -1, 65536], &[0, 1, 65535]);
        check_ranges::<u32>(&db, &[-2, -1, 4_294_967_296], &[0, 1, 4_294_967_295]);
    }
}
<|endoftext|>


<commit_before>//! This module defines a series of convenience modifiers for changing
//! Responses.
//!
//! Modifiers can be used to edit `Response`s through the owning method `set`
//! or the mutating `set_mut`, both of which are defined in the `Set` trait.
//!
//! For Iron, the `Modifier` interface offers extensible and ergonomic response
//! creation while avoiding the introduction of many highly specific `Response`
//! constructors.
//!
//! The simplest case of a modifier is probably the one used to change the
//! return status code:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::status;
//! let r = Response::with(status::NotFound);
//! assert_eq!(r.status.unwrap().to_u16(), 404);
//! ```
//!
//! You can also pass in a tuple of modifiers, they will all be applied. Here's
//! an example of a modifier 2-tuple that will change the status code and the
//! body message:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::status;
//! Response::with((status::ImATeapot, "I am a tea pot!"));
//! ```
//!
//! There is also a `Redirect` modifier:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::status;
//! # use iron::modifiers;
//! # use iron::Url;
//! let url = Url::parse("http://doc.rust-lang.org").unwrap();
//! Response::with((status::Found, modifiers::Redirect(url)));
//! ```
//!
//! The modifiers are applied depending on their type. Currently the easiest
//! way to see how different types are used as modifiers, take a look at [the
//! source code](https://github.com/iron/iron/blob/master/src/modifiers.rs).
//!
//! For more information about the modifier system, see
//! [rust-modifier](https://github.com/reem/rust-modifier).

use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};

use modifier::Modifier;

use hyper::mime::Mime;

use {status, headers, Request, Response, Set, Url};

use mime_types;
use response::{WriteBody, BodyReader};

lazy_static! {
    static ref MIME_TYPES: mime_types::Types = mime_types::Types::new().unwrap();
}

impl Modifier<Response> for Mime {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.headers.set(headers::ContentType(self))
    }
}

impl Modifier<Response> for Box<WriteBody> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.body = Some(self);
    }
}

impl <R: io::Read + Send + 'static> Modifier<Response> for BodyReader<R> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.body = Some(Box::new(self));
    }
}

impl Modifier<Response> for String {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.into_bytes().modify(res);
    }
}

impl Modifier<Response> for Vec<u8> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.headers.set(headers::ContentLength(self.len() as u64));
        res.body = Some(Box::new(self));
    }
}

impl<'a> Modifier<Response> for &'a str {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.to_owned().modify(res);
    }
}

impl<'a> Modifier<Response> for &'a [u8] {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.to_vec().modify(res);
    }
}

impl Modifier<Response> for File {
    fn modify(self, res: &mut Response) {
        // Set the content type based on the file extension if a path is available.
        if let Ok(metadata) = self.metadata() {
            res.headers.set(headers::ContentLength(metadata.len()));
        }

        res.body = Some(Box::new(self));
    }
}

impl<'a> Modifier<Response> for &'a Path {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    fn modify(self, res: &mut Response) {
        File::open(self)
            .expect(&format!("No such file: {}", self.display()))
            .modify(res);

        let mime_str = MIME_TYPES.mime_for_path(self);
        let _ = mime_str.parse().map(|mime: Mime| res.set_mut(mime));
    }
}

impl Modifier<Response> for PathBuf {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    #[inline]
    fn modify(self, res: &mut Response) {
        self.as_path().modify(res);
    }
}

impl Modifier<Response> for status::Status {
    fn modify(self, res: &mut Response) {
        res.status = Some(self);
    }
}

/// A modifier for changing headers on requests and responses.
#[derive(Clone)]
pub struct Header<H: headers::Header + headers::HeaderFormat>(pub H);

impl<H> Modifier<Response> for Header<H>
where H: headers::Header + headers::HeaderFormat {
    fn modify(self, res: &mut Response) {
        res.headers.set(self.0);
    }
}

impl<'a, 'b, H> Modifier<Request<'a, 'b>> for Header<H>
where H: headers::Header + headers::HeaderFormat {
    fn modify(self, res: &mut Request) {
        res.headers.set(self.0);
    }
}

/// A modifier for creating redirect responses.
pub struct Redirect(pub Url);

impl Modifier<Response> for Redirect {
    fn modify(self, res: &mut Response) {
        let Redirect(url) = self;
        res.headers.set(headers::Location(url.to_string()));
    }
}

/// A modifier for creating redirect responses.
pub struct RedirectRaw(pub String);

impl Modifier<Response> for RedirectRaw {
    fn modify(self, res: &mut Response) {
        let RedirectRaw(path) = self;
        res.headers.set(headers::Location(path));
    }
}
<commit_msg>Add some tests for mime type guessing based on path<commit_after>//! This module defines a series of convenience modifiers for changing
//! Responses.
//!
//! Modifiers can be used to edit `Response`s through the owning method `set`
//! or the mutating `set_mut`, both of which are defined in the `Set` trait.
//!
//! For Iron, the `Modifier` interface offers extensible and ergonomic response
//! creation while avoiding the introduction of many highly specific `Response`
//! constructors.
//!
//! The simplest case of a modifier is probably the one used to change the
//! return status code:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::status;
//! let r = Response::with(status::NotFound);
//! assert_eq!(r.status.unwrap().to_u16(), 404);
//! ```
//!
//! You can also pass in a tuple of modifiers, they will all be applied. Here's
//! an example of a modifier 2-tuple that will change the status code and the
//! body message:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::status;
//! Response::with((status::ImATeapot, "I am a tea pot!"));
//! ```
//!
//! There is also a `Redirect` modifier:
//!
//! ```
//! # use iron::prelude::*;
//! # use iron::status;
//! # use iron::modifiers;
//! # use iron::Url;
//! let url = Url::parse("http://doc.rust-lang.org").unwrap();
//! Response::with((status::Found, modifiers::Redirect(url)));
//! ```
//!
//! The modifiers are applied depending on their type. Currently the easiest
//! way to see how different types are used as modifiers, take a look at [the
//! source code](https://github.com/iron/iron/blob/master/src/modifiers.rs).
//!
//! For more information about the modifier system, see
//! [rust-modifier](https://github.com/reem/rust-modifier).

use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};

use modifier::Modifier;

use hyper::mime::Mime;

use {status, headers, Request, Response, Set, Url};

use mime_types;
use response::{WriteBody, BodyReader};

lazy_static! {
    static ref MIME_TYPES: mime_types::Types = mime_types::Types::new().unwrap();
}

impl Modifier<Response> for Mime {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.headers.set(headers::ContentType(self))
    }
}

impl Modifier<Response> for Box<WriteBody> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.body = Some(self);
    }
}

impl <R: io::Read + Send + 'static> Modifier<Response> for BodyReader<R> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.body = Some(Box::new(self));
    }
}

impl Modifier<Response> for String {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.into_bytes().modify(res);
    }
}

impl Modifier<Response> for Vec<u8> {
    #[inline]
    fn modify(self, res: &mut Response) {
        res.headers.set(headers::ContentLength(self.len() as u64));
        res.body = Some(Box::new(self));
    }
}

impl<'a> Modifier<Response> for &'a str {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.to_owned().modify(res);
    }
}

impl<'a> Modifier<Response> for &'a [u8] {
    #[inline]
    fn modify(self, res: &mut Response) {
        self.to_vec().modify(res);
    }
}

impl Modifier<Response> for File {
    fn modify(self, res: &mut Response) {
        // Set the content type based on the file extension if a path is available.
        if let Ok(metadata) = self.metadata() {
            res.headers.set(headers::ContentLength(metadata.len()));
        }

        res.body = Some(Box::new(self));
    }
}

impl<'a> Modifier<Response> for &'a Path {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    fn modify(self, res: &mut Response) {
        File::open(self)
            .expect(&format!("No such file: {}", self.display()))
            .modify(res);

        if let Some(mime) = mime_for_path(self) {
            res.set_mut(mime);
        }
    }
}

impl Modifier<Response> for PathBuf {
    /// Set the body to the contents of the File at this path.
    ///
    /// ## Panics
    ///
    /// Panics if there is no file at the passed-in Path.
    #[inline]
    fn modify(self, res: &mut Response) {
        self.as_path().modify(res);
    }
}

impl Modifier<Response> for status::Status {
    fn modify(self, res: &mut Response) {
        res.status = Some(self);
    }
}

/// A modifier for changing headers on requests and responses.
#[derive(Clone)]
pub struct Header<H: headers::Header + headers::HeaderFormat>(pub H);

impl<H> Modifier<Response> for Header<H>
where H: headers::Header + headers::HeaderFormat {
    fn modify(self, res: &mut Response) {
        res.headers.set(self.0);
    }
}

impl<'a, 'b, H> Modifier<Request<'a, 'b>> for Header<H>
where H: headers::Header + headers::HeaderFormat {
    fn modify(self, res: &mut Request) {
        res.headers.set(self.0);
    }
}

/// A modifier for creating redirect responses.
pub struct Redirect(pub Url);

impl Modifier<Response> for Redirect {
    fn modify(self, res: &mut Response) {
        let Redirect(url) = self;
        res.headers.set(headers::Location(url.to_string()));
    }
}

/// A modifier for creating redirect responses.
pub struct RedirectRaw(pub String);

impl Modifier<Response> for RedirectRaw {
    fn modify(self, res: &mut Response) {
        let RedirectRaw(path) = self;
        res.headers.set(headers::Location(path));
    }
}

fn mime_for_path(path: &Path) -> Option<Mime> {
    let mime_str = MIME_TYPES.mime_for_path(path);
    mime_str.parse().ok()
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_mime_for_path() {
        assert_eq!(mime_for_path(Path::new("foo.txt")),
                   Some("text/plain".parse().unwrap()));
        assert_eq!(mime_for_path(Path::new("foo.jpg")),
                   Some("image/jpeg".parse().unwrap()));
        assert_eq!(mime_for_path(Path::new("foo.zip")),
                   Some("application/zip".parse().unwrap()));
        assert_eq!(mime_for_path(Path::new("foo")),
                   Some("text/plain".parse().unwrap()));
    }
}
<|endoftext|>


<commit_before>use crate::borrow_check::location::{LocationIndex, LocationTable};
use crate::dataflow::indexes::MovePathIndex;
use crate::dataflow::move_paths::{LookupResult, MoveData};
use crate::util::liveness::{categorize, DefUse};
use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc::mir::{Local, Location, Place, ReadOnlyBodyAndCache};
use rustc::ty::subst::GenericArg;

use super::TypeChecker;

type VarPointRelation = Vec<(Local, LocationIndex)>;
type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;

struct UseFactsExtractor<'me> {
    var_defined_at: &'me mut VarPointRelation,
    var_used_at: &'me mut VarPointRelation,
    location_table: &'me LocationTable,
    var_dropped_at: &'me mut VarPointRelation,
    move_data: &'me MoveData<'me>,
    path_accessed_at_base: &'me mut PathPointRelation,
}

// A Visitor to walk through the MIR and extract point-wise facts
impl UseFactsExtractor<'_> {
    fn location_to_index(&self, location: Location) -> LocationIndex {
        self.location_table.mid_index(location)
    }

    fn insert_def(&mut self, local: Local, location: Location) {
        debug!("UseFactsExtractor::insert_def()");
        self.var_defined_at.push((local, self.location_to_index(location)));
    }

    fn insert_use(&mut self, local: Local, location: Location) {
        debug!("UseFactsExtractor::insert_use()");
        self.var_used_at.push((local, self.location_to_index(location)));
    }

    fn insert_drop_use(&mut self, local: Local, location: Location) {
        debug!("UseFactsExtractor::insert_drop_use()");
        self.var_dropped_at.push((local, self.location_to_index(location)));
    }

    fn insert_path_access(&mut self, path: MovePathIndex, location: Location) {
        debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location);
        self.path_accessed_at_base.push((path, self.location_table.start_index(location)));
    }

    fn place_to_mpi(&self, place: &Place<'_>) -> Option<MovePathIndex> {
        match self.move_data.rev_lookup.find(place.as_ref()) {
            LookupResult::Exact(mpi) => Some(mpi),
            LookupResult::Parent(mmpi) => mmpi,
        }
    }
}

impl Visitor<'tcx> for UseFactsExtractor<'_> {
    fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
        match categorize(context) {
            Some(DefUse::Def) => self.insert_def(local, location),
            Some(DefUse::Use) => self.insert_use(local, location),
            Some(DefUse::Drop) => self.insert_drop_use(local, location),
            _ => (),
        }
    }

    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
        self.super_place(place, context, location);
        match context {
            PlaceContext::NonMutatingUse(_) => {
                if let Some(mpi) = self.place_to_mpi(place) {
                    self.insert_path_access(mpi, location);
                }
            }

            PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
                if let Some(mpi) = self.place_to_mpi(place) {
                    self.insert_path_access(mpi, location);
                }
            }
            _ => (),
        }
    }
}

pub(super) fn populate_access_facts(
    typeck: &mut TypeChecker<'_, 'tcx>,
    body: ReadOnlyBodyAndCache<'_, 'tcx>,
    location_table: &LocationTable,
    move_data: &MoveData<'_>,
    dropped_at: &mut Vec<(Local, Location)>,
) {
    debug!("populate_access_facts()");

    if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
        let mut extractor = UseFactsExtractor {
            var_defined_at: &mut facts.var_defined_at,
            var_used_at: &mut facts.var_used_at,
            var_dropped_at: &mut facts.var_dropped_at,
            path_accessed_at_base: &mut facts.path_accessed_at_base,
            location_table,
            move_data,
        };
        extractor.visit_body(body);

        facts.var_dropped_at.extend(
            dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))),
        );

        for (local, local_decl) in body.local_decls.iter_enumerated() {
            debug!(
                "add use_of_var_derefs_origin facts - local={:?}, type={:?}",
                local, local_decl.ty
            );
            let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
            let universal_regions = &typeck.borrowck_context.universal_regions;
            typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
                let region_vid = universal_regions.to_region_vid(region);
                facts.use_of_var_derefs_origin.push((local, region_vid));
            });
        }
    }
}

// For every potentially drop()-touched region `region` in `local`'s type
// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
pub(super) fn add_drop_of_var_derefs_origin(
    typeck: &mut TypeChecker<'_, 'tcx>,
    local: Local,
    kind: &GenericArg<'tcx>,
) {
    debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind);
    if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
        let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
        let universal_regions = &typeck.borrowck_context.universal_regions;
        typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
            let region_vid = universal_regions.to_region_vid(drop_live_region);
            facts.drop_of_var_derefs_origin.push((local, region_vid));
        });
    }
}
<commit_msg>Polonius fact generation: fix path access fact location<commit_after>use crate::borrow_check::location::{LocationIndex, LocationTable};
use crate::dataflow::indexes::MovePathIndex;
use crate::dataflow::move_paths::{LookupResult, MoveData};
use crate::util::liveness::{categorize, DefUse};
use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc::mir::{Local, Location, Place, ReadOnlyBodyAndCache};
use rustc::ty::subst::GenericArg;

use super::TypeChecker;

type VarPointRelation = Vec<(Local, LocationIndex)>;
type PathPointRelation = Vec<(MovePathIndex, LocationIndex)>;

struct UseFactsExtractor<'me> {
    var_defined_at: &'me mut VarPointRelation,
    var_used_at: &'me mut VarPointRelation,
    location_table: &'me LocationTable,
    var_dropped_at: &'me mut VarPointRelation,
    move_data: &'me MoveData<'me>,
    path_accessed_at_base: &'me mut PathPointRelation,
}

// A Visitor to walk through the MIR and extract point-wise facts
impl UseFactsExtractor<'_> {
    fn location_to_index(&self, location: Location) -> LocationIndex {
        self.location_table.mid_index(location)
    }

    fn insert_def(&mut self, local: Local, location: Location) {
        debug!("UseFactsExtractor::insert_def()");
        self.var_defined_at.push((local, self.location_to_index(location)));
    }

    fn insert_use(&mut self, local: Local, location: Location) {
        debug!("UseFactsExtractor::insert_use()");
        self.var_used_at.push((local, self.location_to_index(location)));
    }

    fn insert_drop_use(&mut self, local: Local, location: Location) {
        debug!("UseFactsExtractor::insert_drop_use()");
        self.var_dropped_at.push((local, self.location_to_index(location)));
    }

    fn insert_path_access(&mut self, path: MovePathIndex, location: Location) {
        debug!("UseFactsExtractor::insert_path_access({:?}, {:?})", path, location);
        self.path_accessed_at_base.push((path, self.location_to_index(location)));
    }

    fn place_to_mpi(&self, place: &Place<'_>) -> Option<MovePathIndex> {
        match self.move_data.rev_lookup.find(place.as_ref()) {
            LookupResult::Exact(mpi) => Some(mpi),
            LookupResult::Parent(mmpi) => mmpi,
        }
    }
}

impl Visitor<'tcx> for UseFactsExtractor<'_> {
    fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
        match categorize(context) {
            Some(DefUse::Def) => self.insert_def(local, location),
            Some(DefUse::Use) => self.insert_use(local, location),
            Some(DefUse::Drop) => self.insert_drop_use(local, location),
            _ => (),
        }
    }

    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
        self.super_place(place, context, location);
        match context {
            PlaceContext::NonMutatingUse(_) => {
                if let Some(mpi) = self.place_to_mpi(place) {
                    self.insert_path_access(mpi, location);
                }
            }

            PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
                if let Some(mpi) = self.place_to_mpi(place) {
                    self.insert_path_access(mpi, location);
                }
            }
            _ => (),
        }
    }
}

pub(super) fn populate_access_facts(
    typeck: &mut TypeChecker<'_, 'tcx>,
    body: ReadOnlyBodyAndCache<'_, 'tcx>,
    location_table: &LocationTable,
    move_data: &MoveData<'_>,
    dropped_at: &mut Vec<(Local, Location)>,
) {
    debug!("populate_access_facts()");

    if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
        let mut extractor = UseFactsExtractor {
            var_defined_at: &mut facts.var_defined_at,
            var_used_at: &mut facts.var_used_at,
            var_dropped_at: &mut facts.var_dropped_at,
            path_accessed_at_base: &mut facts.path_accessed_at_base,
            location_table,
            move_data,
        };
        extractor.visit_body(body);

        facts.var_dropped_at.extend(
            dropped_at.iter().map(|&(local, location)| (local, location_table.mid_index(location))),
        );

        for (local, local_decl) in body.local_decls.iter_enumerated() {
            debug!(
                "add use_of_var_derefs_origin facts - local={:?}, type={:?}",
                local, local_decl.ty
            );
            let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
            let universal_regions = &typeck.borrowck_context.universal_regions;
            typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
                let region_vid = universal_regions.to_region_vid(region);
                facts.use_of_var_derefs_origin.push((local, region_vid));
            });
        }
    }
}

// For every potentially drop()-touched region `region` in `local`'s type
// (`kind`), emit a Polonius `use_of_var_derefs_origin(local, origin)` fact.
pub(super) fn add_drop_of_var_derefs_origin(
    typeck: &mut TypeChecker<'_, 'tcx>,
    local: Local,
    kind: &GenericArg<'tcx>,
) {
    debug!("add_drop_of_var_derefs_origin(local={:?}, kind={:?}", local, kind);
    if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
        let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
        let universal_regions = &typeck.borrowck_context.universal_regions;
        typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
            let region_vid = universal_regions.to_region_vid(drop_live_region);
            facts.drop_of_var_derefs_origin.push((local, region_vid));
        });
    }
}
<|endoftext|>


<commit_before>use ::{KeyType, ValueType};

use wal_file::KeyValuePair;

use std::iter::{Peekable, empty, Map};
use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Entry;
use std::collections::btree_map::Entry::{Occupied, Vacant};
use std::collections::btree_map;
use std::collections::btree_set;

pub struct MultiMap<K: KeyType, V: ValueType> {
    multi_map: BTreeMap<K, BTreeSet<V>>,
    count: usize  // total number of KV pairs
}

pub struct MultiMapIterator<'a, K: KeyType + 'a, V: ValueType + 'a> {
    cur_key: Option<&'a K>,
    key_it: btree_map::Iter<'a,K,BTreeSet<V>>,
    value_it: Option<btree_set::Iter<'a,V>>,
}

impl <'a, K: KeyType, V: ValueType> MultiMap<K,V> {
    pub fn new() -> MultiMap<K,V> {
        return MultiMap{multi_map: BTreeMap::<K,BTreeSet<V>>::new(), count: 0};
    }

    pub fn insert(&mut self, key: K, value: V) -> usize {
        self.count += 1;

        if let Some(set) = self.multi_map.get_mut(&key) {
            set.insert(value);
            return self.count;
        }

        let mut set = BTreeSet::<V>::new();

        set.insert(value);

        self.multi_map.insert(key, set);

        return self.count;
    }

    pub fn delete(&mut self, key: K, value: V) -> usize {
        if let Occupied(mut entry) = self.multi_map.entry(key) {

            if entry.get_mut().remove(&value) {
                self.count -= 1;
            } else {
                println!("DID NOT FIND");
            }

            if entry.get().is_empty() {
                entry.remove_entry();
            }
        } else {
            println!("NOT FOUND!!!");
        }

        return self.count;
    }

    pub fn size(&self) -> usize {
        return self.count;
    }
}

impl <'a, K: KeyType, V: ValueType> IntoIterator for &'a mut MultiMap<K,V> {
    type Item = KeyValuePair<K,V>;
    type IntoIter = MultiMapIterator<'a,K,V>;

    fn into_iter(self) -> Self::IntoIter {
        let mut key_it = self.multi_map.iter();
        let cur_entry = key_it.next();

        // check to see if our map is empty
        if cur_entry.is_none() {
            return MultiMapIterator{cur_key: None, key_it: key_it, value_it: None};
        }

        // safe to call unwrap as we tested above
        let (cur_key, cur_set) = cur_entry.unwrap();

        return MultiMapIterator{cur_key: Some(cur_key), key_it: key_it, value_it: Some(cur_set.iter())};
    }
}

impl <'a, K: KeyType, V: ValueType> Iterator for MultiMapIterator<'a,K,V> {
    type Item = KeyValuePair<K,V>;

    fn next(&mut self) -> Option<Self::Item> {
        // this is our invariant, when it's None we've gone through everything
        if self.cur_key.is_none() {
            return None
        }

        // should be safe to call unwrap here, because we checked for None above
        let mut cur_val = self.value_it.as_mut().unwrap().next();

        // check to see if we've gone through everything in the set
        if cur_val.is_none() {
            let cur_entry = self.key_it.next(); // increment our key iterator

            if cur_entry.is_none() {
                self.cur_key = None; // set our invariant
                return None;
            }

            // safe to call unwrap because we checked it above
            let (cur_key, cur_set) = cur_entry.unwrap();

            self.cur_key = Some(cur_key); // set our key
            self.value_it = Some(cur_set.iter()); // set our value iterator
            cur_val = self.value_it.as_mut().unwrap().next(); // set our current value
        }

        return Some(KeyValuePair{key: self.cur_key.unwrap().clone(), value: cur_val.unwrap().clone()});
    }
}

#[cfg(test)]
mod tests {
    use multi_map::{MultiMap, MultiMapIterator};
    use wal_file::KeyValuePair;

    #[test]
    fn test_insert() {
        let mut mmap = MultiMap::<i32,String>::new();

        assert!(mmap.insert(12, String::from("abc")) == 1);
        assert!(mmap.insert(23, String::from("abc")) == 2);
        assert!(mmap.insert(23, String::from("def")) == 3);

        let mut it = mmap.into_iter();

        let e1 = it.next().unwrap();
        assert!(12 == e1.key);
        assert!(String::from("abc") == e1.value);

        let e2 = it.next().unwrap();
        assert!(23 == e2.key);
        assert!(String::from("abc") == e2.value);

        let e3 = it.next().unwrap();
        assert!(23 == e3.key);
        assert!(String::from("def") == e3.value);
    }

    #[test]
    fn test_delete() {
        let mut mmap = MultiMap::<i32,String>::new();

        assert!(mmap.insert(12, String::from("abc")) == 1);
        assert!(mmap.insert(23, String::from("abc")) == 2);
        assert!(mmap.insert(23, String::from("def")) == 3);

        assert!(mmap.size() == 3);

        assert!(mmap.delete(12, String::from("abc")) == 2);
        assert!(mmap.delete(23, String::from("abc")) == 1);
        assert!(mmap.delete(23, String::from("abc")) == 1); // should NOT find this one
        assert!(mmap.delete(23, String::from("def")) == 0);

        assert!(mmap.size() == 0);

        let mut it = mmap.into_iter();

        assert!(it.next() == None);
    }
}

<commit_msg>Removed debug, and added future TODO<commit_after>use ::{KeyType, ValueType};

use wal_file::KeyValuePair;

use std::iter::{Peekable, empty, Map};
use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Entry;
use std::collections::btree_map::Entry::{Occupied, Vacant};
use std::collections::btree_map;
use std::collections::btree_set;

pub struct MultiMap<K: KeyType, V: ValueType> {
    multi_map: BTreeMap<K, BTreeSet<V>>,
    count: usize  // total number of KV pairs
}

pub struct MultiMapIterator<'a, K: KeyType + 'a, V: ValueType + 'a> {
    cur_key: Option<&'a K>,
    key_it: btree_map::Iter<'a,K,BTreeSet<V>>,
    value_it: Option<btree_set::Iter<'a,V>>,
}

impl <'a, K: KeyType, V: ValueType> MultiMap<K,V> {
    pub fn new() -> MultiMap<K,V> {
        return MultiMap{multi_map: BTreeMap::<K,BTreeSet<V>>::new(), count: 0};
    }

    pub fn insert(&mut self, key: K, value: V) -> usize {
        self.count += 1;

        if let Some(set) = self.multi_map.get_mut(&key) {
            set.insert(value);
            return self.count;
        }

        let mut set = BTreeSet::<V>::new();

        set.insert(value);

        self.multi_map.insert(key, set);

        return self.count;
    }

    /*
     * Might want to re-think this and return an Error
     * as there isn't a great way to tell the user that a
     * key or value wasn't found
     */
    pub fn delete(&mut self, key: K, value: V) -> usize {
        if let Occupied(mut entry) = self.multi_map.entry(key) {

            if entry.get_mut().remove(&value) {
                self.count -= 1;
            }

            if entry.get().is_empty() {
                entry.remove_entry();
            }
        }

        return self.count;
    }

    pub fn size(&self) -> usize {
        return self.count;
    }
}

impl <'a, K: KeyType, V: ValueType> IntoIterator for &'a mut MultiMap<K,V> {
    type Item = KeyValuePair<K,V>;
    type IntoIter = MultiMapIterator<'a,K,V>;

    fn into_iter(self) -> Self::IntoIter {
        let mut key_it = self.multi_map.iter();
        let cur_entry = key_it.next();

        // check to see if our map is empty
        if cur_entry.is_none() {
            return MultiMapIterator{cur_key: None, key_it: key_it, value_it: None};
        }

        // safe to call unwrap as we tested above
        let (cur_key, cur_set) = cur_entry.unwrap();

        return MultiMapIterator{cur_key: Some(cur_key), key_it: key_it, value_it: Some(cur_set.iter())};
    }
}

impl <'a, K: KeyType, V: ValueType> Iterator for MultiMapIterator<'a,K,V> {
    type Item = KeyValuePair<K,V>;

    fn next(&mut self) -> Option<Self::Item> {
        // this is our invariant, when it's None we've gone through everything
        if self.cur_key.is_none() {
            return None
        }

        // should be safe to call unwrap here, because we checked for None above
        let mut cur_val = self.value_it.as_mut().unwrap().next();

        // check to see if we've gone through everything in the set
        if cur_val.is_none() {
            let cur_entry = self.key_it.next(); // increment our key iterator

            if cur_entry.is_none() {
                self.cur_key = None; // set our invariant
                return None;
            }

            // safe to call unwrap because we checked it above
            let (cur_key, cur_set) = cur_entry.unwrap();

            self.cur_key = Some(cur_key); // set our key
            self.value_it = Some(cur_set.iter()); // set our value iterator
            cur_val = self.value_it.as_mut().unwrap().next(); // set our current value
        }

        return Some(KeyValuePair{key: self.cur_key.unwrap().clone(), value: cur_val.unwrap().clone()});
    }
}

#[cfg(test)]
mod tests {
    use multi_map::{MultiMap, MultiMapIterator};
    use wal_file::KeyValuePair;

    #[test]
    fn test_insert() {
        let mut mmap = MultiMap::<i32,String>::new();

        assert!(mmap.insert(12, String::from("abc")) == 1);
        assert!(mmap.insert(23, String::from("abc")) == 2);
        assert!(mmap.insert(23, String::from("def")) == 3);

        let mut it = mmap.into_iter();

        let e1 = it.next().unwrap();
        assert!(12 == e1.key);
        assert!(String::from("abc") == e1.value);

        let e2 = it.next().unwrap();
        assert!(23 == e2.key);
        assert!(String::from("abc") == e2.value);

        let e3 = it.next().unwrap();
        assert!(23 == e3.key);
        assert!(String::from("def") == e3.value);
    }

    #[test]
    fn test_delete() {
        let mut mmap = MultiMap::<i32,String>::new();

        assert!(mmap.insert(12, String::from("abc")) == 1);
        assert!(mmap.insert(23, String::from("abc")) == 2);
        assert!(mmap.insert(23, String::from("def")) == 3);

        assert!(mmap.size() == 3);

        assert!(mmap.delete(12, String::from("abc")) == 2);
        assert!(mmap.delete(23, String::from("abc")) == 1);
        assert!(mmap.delete(23, String::from("abc")) == 1); // should NOT find this one
        assert!(mmap.delete(23, String::from("def")) == 0);

        assert!(mmap.size() == 0);

        let mut it = mmap.into_iter();

        assert!(it.next() == None);
    }
}

<|endoftext|>


<commit_before>use std::io::{self, Write};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

pub fn heading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "=")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn subheading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "-")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn progress(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn info(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn error(content: String) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Red))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn list(items: Vec<&str>) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "") {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    items
        .iter()
        .for_each(|content| match writeln!(&mut stdout, "- {}", content) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        })
}

pub fn pause() {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    loop {
        let prompt = "Enter 'Done' when ready to continue:";

        match writeln!(&mut stdout, "\n{}", prompt) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        let mut input = String::new();

        match io::stdin().read_line(&mut input) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        if input.contains("Done") {
            match stdout.reset() {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            break;
        } else {
            continue;
        }
    }

    let x = 3.1415;
    let r = 8.0;
    println!("the area of the circle is {}", x * r * r);
}

fn underline(content: &str, symbol: &str) -> String {
                content.chars().map(|_| symbol).collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_underline() {
        assert_eq!(underline("Some line", "="), "=========");
        assert_eq!(underline("Another line", "-"), "------------");
    }
}
<commit_msg>Fix formatting<commit_after>use std::io::{self, Write};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

pub fn heading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "=")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn subheading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "-")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn progress(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn info(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn error(content: String) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Red))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn list(items: Vec<&str>) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "") {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    items
        .iter()
        .for_each(|content| match writeln!(&mut stdout, "- {}", content) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        })
}

pub fn pause() {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    loop {
        let prompt = "Enter 'Done' when ready to continue:";

        match writeln!(&mut stdout, "\n{}", prompt) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        let mut input = String::new();

        match io::stdin().read_line(&mut input) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        if input.contains("Done") {
            match stdout.reset() {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            break;
        } else {
            continue;
        }
    }
}

fn underline(content: &str, symbol: &str) -> String {
    content.chars().map(|_| symbol).collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_underline() {
        assert_eq!(underline("Some line", "="), "=========");
        assert_eq!(underline("Another line", "-"), "------------");
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

pub fn heading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "=")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn subheading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "-")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn progress(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn info(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn error(content: String) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Red))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn list(items: Vec<&str>) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "") {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    items
        .iter()
        .for_each(|content| match writeln!(&mut stdout, "- {}", content) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        })
}

pub fn pause() {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    loop {
        let prompt = "Enter 'Done' when ready to continue:";

        match writeln!(&mut stdout, "\n{}", prompt) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        let mut input = String::new();

        match io::stdin().read_line(&mut input) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        if input.contains("Done") {
            match stdout.reset() {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            break;
        } else {
            continue;
        }
    }
}

fn underline(content: &str, symbol: &str) -> String {
    content.chars().map(|_| symbol).collect()
}
<commit_msg>Add one unit test so CI has passing tests to start<commit_after>use std::io::{self, Write};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

pub fn heading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "=")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn subheading(content: &str) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Cyan))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}\n{}", content, underline(content, "-")) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn progress(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn info(content: String) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn error(content: String) {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Red))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match writeln!(&mut stdout, "\n{}", content) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    match stdout.reset() {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }
}

pub fn list(items: Vec<&str>) {
    let mut stdout = io::stdout();

    match writeln!(&mut stdout, "") {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    items
        .iter()
        .for_each(|content| match writeln!(&mut stdout, "- {}", content) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        })
}

pub fn pause() {
    let mut stdout = StandardStream::stdout(ColorChoice::Always);

    match stdout.set_color(ColorSpec::new().set_fg(Some(Color::Yellow))) {
        Ok(_) => (),
        Err(error) => panic!("There was a problem: {:?}", error),
    }

    loop {
        let prompt = "Enter 'Done' when ready to continue:";

        match writeln!(&mut stdout, "\n{}", prompt) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        let mut input = String::new();

        match io::stdin().read_line(&mut input) {
            Ok(_) => (),
            Err(error) => panic!("There was a problem: {:?}", error),
        }

        if input.contains("Done") {
            match stdout.reset() {
                Ok(_) => (),
                Err(error) => panic!("There was a problem: {:?}", error),
            }

            break;
        } else {
            continue;
        }
    }
}

fn underline(content: &str, symbol: &str) -> String {
    content.chars().map(|_| symbol).collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_underline() {
        assert_eq!(underline("Some line", "="), "=========");
        assert_eq!(underline("Another line", "-"), "------------");
    }
}
<|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

pub static DEFAULT_SIGNAL: usize = 15;

pub struct Signal<'a> {
    pub name: &'a str,
    pub value: usize,
}

/*

Linux Programmer's Manual

 1 HUP      2 INT      3 QUIT     4 ILL      5 TRAP     6 ABRT     7 BUS
 8 FPE      9 KILL    10 USR1    11 SEGV    12 USR2    13 PIPE    14 ALRM
15 TERM    16 STKFLT  17 CHLD    18 CONT    19 STOP    20 TSTP    21 TTIN
22 TTOU    23 URG     24 XCPU    25 XFSZ    26 VTALRM  27 PROF    28 WINCH
29 POLL    30 PWR     31 SYS

*/

#[cfg(target_os = "linux")]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "BUS",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "USR1",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "USR2",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "STKFLT",
        value: 16,
    },
    Signal {
        name: "CHLD",
        value: 17,
    },
    Signal {
        name: "CONT",
        value: 18,
    },
    Signal {
        name: "STOP",
        value: 19,
    },
    Signal {
        name: "TSTP",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "URG",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "POLL",
        value: 29,
    },
    Signal {
        name: "PWR",
        value: 30,
    },
    Signal {
        name: "SYS",
        value: 31,
    },
];

/*

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html

No    Name         Default Action       Description
1     SIGHUP       terminate process    terminal line hangup
2     SIGINT       terminate process    interrupt program
3     SIGQUIT      create core image    quit program
4     SIGILL       create core image    illegal instruction
5     SIGTRAP      create core image    trace trap
6     SIGABRT      create core image    abort program (formerly SIGIOT)
7     SIGEMT       create core image    emulate instruction executed
8     SIGFPE       create core image    floating-point exception
9     SIGKILL      terminate process    kill program
10    SIGBUS       create core image    bus error
11    SIGSEGV      create core image    segmentation violation
12    SIGSYS       create core image    non-existent system call invoked
13    SIGPIPE      terminate process    write on a pipe with no reader
14    SIGALRM      terminate process    real-time timer expired
15    SIGTERM      terminate process    software termination signal
16    SIGURG       discard signal       urgent condition present on socket
17    SIGSTOP      stop process         stop (cannot be caught or ignored)
18    SIGTSTP      stop process         stop signal generated from keyboard
19    SIGCONT      discard signal       continue after stop
20    SIGCHLD      discard signal       child status has changed
21    SIGTTIN      stop process         background read attempted from control terminal
22    SIGTTOU      stop process         background write attempted to control terminal
23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
28    SIGWINCH     discard signal       Window size change
29    SIGINFO      discard signal       status request from keyboard
30    SIGUSR1      terminate process    User defined signal 1
31    SIGUSR2      terminate process    User defined signal 2

*/

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "EMT",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "BUS",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "SYS",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "URG",
        value: 16,
    },
    Signal {
        name: "STOP",
        value: 17,
    },
    Signal {
        name: "TSTP",
        value: 18,
    },
    Signal {
        name: "CONT",
        value: 19,
    },
    Signal {
        name: "CHLD",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "IO",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "INFO",
        value: 29,
    },
    Signal {
        name: "USR1",
        value: 30,
    },
    Signal {
        name: "USR2",
        value: 31,
    },
];

pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
    if signal_name_or_value == "0" {
        return Some(0);
    }
    for signal in &ALL_SIGNALS {
        let long_name = format!("SIG{}", signal.name);
        if signal.name == signal_name_or_value || (signal_name_or_value == signal.value.to_string())
            || (long_name == signal_name_or_value)
        {
            return Some(signal.value);
        }
    }
    None
}

#[inline(always)]
pub fn is_signal(num: usize) -> bool {
    // Named signals start at 1
    num <= ALL_SIGNALS.len()
}

#[test]
fn signals_all_contiguous() {
    for (i, signal) in ALL_SIGNALS.iter().enumerate() {
        assert_eq!(signal.value, i + 1);
    }
}

#[test]
fn signals_all_are_signal() {
    for signal in &ALL_SIGNALS {
        assert!(is_signal(signal.value));
    }
}

#[test]
fn signal_by_value() {
    assert_eq!(signal_by_name_or_value("0"), Some(0));
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(&signal.value.to_string()), Some(signal.value));
    }
}

#[test]
fn signal_by_short_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(signal.name), Some(signal.value));
    }
}

#[test]
fn signal_by_long_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(&format!("SIG{}", signal.name)), Some(signal.value));
    }
}
<commit_msg>Don't allocate in signal_by_name_or_value<commit_after>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

pub static DEFAULT_SIGNAL: usize = 15;

pub struct Signal<'a> {
    pub name: &'a str,
    pub value: usize,
}

/*

Linux Programmer's Manual

 1 HUP      2 INT      3 QUIT     4 ILL      5 TRAP     6 ABRT     7 BUS
 8 FPE      9 KILL    10 USR1    11 SEGV    12 USR2    13 PIPE    14 ALRM
15 TERM    16 STKFLT  17 CHLD    18 CONT    19 STOP    20 TSTP    21 TTIN
22 TTOU    23 URG     24 XCPU    25 XFSZ    26 VTALRM  27 PROF    28 WINCH
29 POLL    30 PWR     31 SYS

*/

#[cfg(target_os = "linux")]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "BUS",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "USR1",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "USR2",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "STKFLT",
        value: 16,
    },
    Signal {
        name: "CHLD",
        value: 17,
    },
    Signal {
        name: "CONT",
        value: 18,
    },
    Signal {
        name: "STOP",
        value: 19,
    },
    Signal {
        name: "TSTP",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "URG",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "POLL",
        value: 29,
    },
    Signal {
        name: "PWR",
        value: 30,
    },
    Signal {
        name: "SYS",
        value: 31,
    },
];

/*

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html

No    Name         Default Action       Description
1     SIGHUP       terminate process    terminal line hangup
2     SIGINT       terminate process    interrupt program
3     SIGQUIT      create core image    quit program
4     SIGILL       create core image    illegal instruction
5     SIGTRAP      create core image    trace trap
6     SIGABRT      create core image    abort program (formerly SIGIOT)
7     SIGEMT       create core image    emulate instruction executed
8     SIGFPE       create core image    floating-point exception
9     SIGKILL      terminate process    kill program
10    SIGBUS       create core image    bus error
11    SIGSEGV      create core image    segmentation violation
12    SIGSYS       create core image    non-existent system call invoked
13    SIGPIPE      terminate process    write on a pipe with no reader
14    SIGALRM      terminate process    real-time timer expired
15    SIGTERM      terminate process    software termination signal
16    SIGURG       discard signal       urgent condition present on socket
17    SIGSTOP      stop process         stop (cannot be caught or ignored)
18    SIGTSTP      stop process         stop signal generated from keyboard
19    SIGCONT      discard signal       continue after stop
20    SIGCHLD      discard signal       child status has changed
21    SIGTTIN      stop process         background read attempted from control terminal
22    SIGTTOU      stop process         background write attempted to control terminal
23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
28    SIGWINCH     discard signal       Window size change
29    SIGINFO      discard signal       status request from keyboard
30    SIGUSR1      terminate process    User defined signal 1
31    SIGUSR2      terminate process    User defined signal 2

*/

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "EMT",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "BUS",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "SYS",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "URG",
        value: 16,
    },
    Signal {
        name: "STOP",
        value: 17,
    },
    Signal {
        name: "TSTP",
        value: 18,
    },
    Signal {
        name: "CONT",
        value: 19,
    },
    Signal {
        name: "CHLD",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "IO",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "INFO",
        value: 29,
    },
    Signal {
        name: "USR1",
        value: 30,
    },
    Signal {
        name: "USR2",
        value: 31,
    },
];

pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
    if let Ok(value) = signal_name_or_value.parse() {
        if is_signal(value) {
            return Some(value);
        } else {
            return None;
        }
    }
    let signal_name = if signal_name_or_value.starts_with("SIG") {
        &signal_name_or_value[3..]
    } else {
        &signal_name_or_value[..]
    };

    ALL_SIGNALS
        .iter()
        .find(|s| s.name == signal_name)
        .map(|s| s.value)
}

#[inline(always)]
pub fn is_signal(num: usize) -> bool {
    // Named signals start at 1
    num <= ALL_SIGNALS.len()
}

#[test]
fn signals_all_contiguous() {
    for (i, signal) in ALL_SIGNALS.iter().enumerate() {
        assert_eq!(signal.value, i + 1);
    }
}

#[test]
fn signals_all_are_signal() {
    for signal in &ALL_SIGNALS {
        assert!(is_signal(signal.value));
    }
}

#[test]
fn signal_by_value() {
    assert_eq!(signal_by_name_or_value("0"), Some(0));
    for signal in &ALL_SIGNALS {
        assert_eq!(
            signal_by_name_or_value(&signal.value.to_string()),
            Some(signal.value)
        );
    }
}

#[test]
fn signal_by_short_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(signal.name), Some(signal.value));
    }
}

#[test]
fn signal_by_long_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(
            signal_by_name_or_value(&format!("SIG{}", signal.name)),
            Some(signal.value)
        );
    }
}
<|endoftext|>