<commit_before>use crate::error::{Error,
                   Result};
use hex::FromHex;
use std::{convert::{TryFrom,
                    TryInto},
          fmt,
          fs::File,
          io::{BufReader,
               Read},
          path::Path,
          ptr,
          str::FromStr};

const BUF_SIZE: usize = 1024;

const HASH_DIGEST_SIZE: usize = 32;

/// Convenience wrapper type for a 32-byte Blake2b hash digest.
///
/// Implements secure equality comparison, as well as hex-encoding via
/// `std::fmt::Display`.
///
/// There are intentionally no explicit constructors; to get a
/// instance, you'll need to either convert it directly from a `&[u8]`
/// or parse it from a hex string.
#[derive(Clone, Debug)]
pub struct Blake2bHash([u8; HASH_DIGEST_SIZE]);

impl TryFrom<Vec<u8>> for Blake2bHash {
    type Error = Error;

    // Create a Blake2bHash from a vector of bytes. Ensures the vector
    // is the correct length for the hash.
    fn try_from(value: Vec<u8>) -> Result<Self> {
        let boxed: Box<[u8]> = value.into_boxed_slice();
        let boxed: Box<[u8; HASH_DIGEST_SIZE]> =
            boxed.try_into().map_err(|_| {
                                 Error::CryptoError(format!("Did not get {} bytes for digest",
                                                            HASH_DIGEST_SIZE))
                             })?;
        Ok(Blake2bHash(*boxed))
    }
}

impl AsRef<[u8]> for Blake2bHash {
    fn as_ref(&self) -> &[u8] { &self.0 }
}

impl PartialEq for Blake2bHash {
    /// Implement secure equality comparison for our hashes here so we
    /// don't have to think about it elsewhere.
    // Strictly speaking, secure equality comparison shouldn't be
    // necessary; however, having a type encapsulate this gives us a
    // convenient way to modify this in the future.
    fn eq(&self, other: &Blake2bHash) -> bool { crate::crypto::secure_eq(self, other) }
}

impl Eq for Blake2bHash {}

impl fmt::Display for Blake2bHash {
    /// Displays a Blake2bHash as a lowercase hex-encoded string.
    ///
    /// Due to historical precedent, the lowercasing *is* significant,
    /// as we sign the lowercase hex-encoded version of a Blake2b
    /// hash, and not simply the Blake2b hash itself, when we sign a
    /// HART file.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // hex::encode currently outputs lowercase strings, but we
        // want to strictly enforce this and guard against any future
        // changes to that crate.
        hex::encode(self).to_lowercase().fmt(f)
    }
}

impl FromStr for Blake2bHash {
    type Err = Error;

    /// Convert a hex-encoded byte string into a Blake2bHash. Ensures
    /// the string represents a byte array of proper length.
    ///
    /// Case of the incoming string is not significant (e.g.,
    /// "DEADBEEF" and "deadbeef" are equivalent).
    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        // FromHex has an implementation for [u8; 32], so this ensures
        // the proper length of bytes... well, that and the compiler,
        // of course :)
        FromHex::from_hex(s).map(Self).map_err(|e| {
                                          Error::CryptoError(format!("Could not parse \
                                                                      Blake2bHash from string: {}",
                                                                     e))
                                      })
    }
}

////////////////////////////////////////////////////////////////////////

/// Calculate the BLAKE2b hash of a file, return as a hex string
/// digest size = 32 BYTES
/// NOTE: the hashing is keyless
pub fn hash_file<P>(filename: P) -> Result<String>
    where P: AsRef<Path>
{
    let file = File::open(filename.as_ref())?;
    let mut reader = BufReader::new(file);
    hash_reader(&mut reader)
}

pub fn hash_string(data: &str) -> String {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES as usize];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    #[allow(clippy::cast_ptr_alignment)]
    let pst = st.as_mut_ptr() as *mut libsodium_sys::crypto_generichash_state;
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    hex::encode(out)
}

pub fn hash_bytes(data: &[u8]) -> String {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES as usize];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    #[allow(clippy::cast_ptr_alignment)]
    let pst = st.as_mut_ptr() as *mut libsodium_sys::crypto_generichash_state;
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    hex::encode(out)
}

pub fn hash_reader(reader: &mut dyn Read) -> Result<String> {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES as usize];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    #[allow(clippy::cast_ptr_alignment)]
    let pst = st.as_mut_ptr() as *mut libsodium_sys::crypto_generichash_state;
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
    }
    let mut buf = [0u8; BUF_SIZE];
    loop {
        let bytes_read = reader.read(&mut buf)?;
        if bytes_read == 0 {
            break;
        }
        let chunk = &buf[0..bytes_read];
        unsafe {
            libsodium_sys::crypto_generichash_update(pst, chunk.as_ptr(), chunk.len() as u64);
        }
    }
    unsafe {
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    Ok(hex::encode(out))
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use std::fs::{self,
                  File};
    #[allow(unused_imports)]
    use std::io;
    use std::{env,
              path::PathBuf};

    use super::{super::test_support::*,
                *};
    #[cfg(feature = "functional")]
    use hyper::{header,
                Client,
                Url};

    #[allow(dead_code)]
    fn mk_local_tmpdir() -> PathBuf {
        let dir = env::current_exe().unwrap()
                                    .parent()
                                    .unwrap()
                                    .parent()
                                    .unwrap()
                                    .parent()
                                    .unwrap()
                                    .parent()
                                    .unwrap()
                                    .parent()
                                    .unwrap()
                                    .join("tmp");
        fs::create_dir_all(&dir).unwrap();
        dir
    }

    #[test]
    fn hash_file_working() {
        // The expected values were computed using the `b2sum` program from
        // https://github.com/dchest/b2sum using the the `-s=32` option. For example:
        //      b2sum -s=32 signme.dat

        let computed = hash_file(&fixture("signme.dat")).unwrap();
        let expected = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.sig.key")).unwrap();
        let expected = "e966844bbc50b7a3a6d81e94dd38e27b92814b944095a8e55f1780921bfcfbe1";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.pub")).unwrap();
        let expected = "b80c4f412f9a0a7727b6e6f115e1b5fa3bae79ad2fcf47f769ed4e42cfb12265";
        assert_eq!(computed, expected);
    }

    #[test]
    #[cfg(feature = "functional")]
    fn hash_file_large_binary() {
        let url = "http://ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.3.tar.gz";
        let dst: PathBuf = {
            let file = mk_local_tmpdir().join(url.rsplit('/').next().unwrap());
            if !file.is_file() {
                let client = match env::var("http_proxy") {
                    Ok(url) => {
                        let url = Url::parse(&url).unwrap();
                        Client::with_http_proxy(url.host_str().unwrap().to_string(),
                                                url.port_or_known_default().unwrap())
                    }
                    _ => Client::new(),
                };
                let mut response = client.get(url)
                                         .header(header::Connection::close())
                                         .send()
                                         .unwrap();
                let mut f = File::create(&file).unwrap();
                io::copy(&mut response, &mut f).unwrap();
            }
            file
        };
        let computed = hash_file(&dst);
        let expected = "ba640dc063f0ed27e60b38dbb7cf19778cf7805d9fc91eb129fb68b409d46414";
        assert_eq!(computed, expected);
    }

    mod blake2bhash {
        use super::*;

        #[test]
        fn eq() {
            let zeroes = Blake2bHash([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                      0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                      0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]);

            let ones = Blake2bHash([1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                    1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                    1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]);

            assert_ne!(zeroes, ones);
            assert_eq!(zeroes, zeroes);
            assert_eq!(ones, ones);
        }

        #[test]
        fn display() {
            let ones = Blake2bHash([1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                    1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                    1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]);
            assert_eq!(ones.to_string(),
                       "0101010101010101010101010101010101010101010101010101010101010101");
        }

        #[test]
        fn from_str_good() {
            // Exactly 32 bytes long
            let h = "0101010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_ok());
        }

        #[test]
        fn from_str_short() {
            // This is one byte too short
            let h = "01010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_err());
        }
        #[test]
        fn from_str_long() {
            // This is one byte too long
            let h = "010101010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_err());
        }

        #[test]
        fn from_str_case_is_insignificant() {
            let lower_case = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
            let upper_case = "20590A52C4F00588C500328B16D466C982A26FABAA5FA4DCC83052DD0A84F233";

            let l = lower_case.parse::<Blake2bHash>().unwrap();
            let u = upper_case.parse::<Blake2bHash>().unwrap();

            assert_eq!(l, u);
        }

        #[test]
        fn from_str_display_round_trip() {
            let input = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
            let output = input.parse::<Blake2bHash>().unwrap().to_string();
            assert_eq!(output, input);
        }
    }
}
<commit_msg>[REFACTOR] HASH_DIGEST_SIZE == crypto_generichash_BYTES<commit_after>use crate::error::{Error,
                   Result};
use hex::FromHex;
use std::{convert::{TryFrom,
                    TryInto},
          fmt,
          fs::File,
          io::{BufReader,
               Read},
          path::Path,
          ptr,
          str::FromStr};

const BUF_SIZE: usize = 1024;

/// The size of a Blake2b hash digest (32 bytes)
const HASH_DIGEST_SIZE: usize = libsodium_sys::crypto_generichash_BYTES as usize;

/// Convenience wrapper type for a 32-byte Blake2b hash digest.
///
/// Implements secure equality comparison, as well as hex-encoding via
/// `std::fmt::Display`.
///
/// There are intentionally no explicit constructors; to get a
/// instance, you'll need to either convert it directly from a `&[u8]`
/// or parse it from a hex string.
#[derive(Clone, Debug)]
pub struct Blake2bHash([u8; HASH_DIGEST_SIZE]);

impl TryFrom<Vec<u8>> for Blake2bHash {
    type Error = Error;

    // Create a Blake2bHash from a vector of bytes. Ensures the vector
    // is the correct length for the hash.
    fn try_from(value: Vec<u8>) -> Result<Self> {
        let boxed: Box<[u8]> = value.into_boxed_slice();
        let boxed: Box<[u8; HASH_DIGEST_SIZE]> =
            boxed.try_into().map_err(|_| {
                                 Error::CryptoError(format!("Did not get {} bytes for digest",
                                                            HASH_DIGEST_SIZE))
                             })?;
        Ok(Blake2bHash(*boxed))
    }
}

impl AsRef<[u8]> for Blake2bHash {
    fn as_ref(&self) -> &[u8] { &self.0 }
}

impl PartialEq for Blake2bHash {
    /// Implement secure equality comparison for our hashes here so we
    /// don't have to think about it elsewhere.
    // Strictly speaking, secure equality comparison shouldn't be
    // necessary; however, having a type encapsulate this gives us a
    // convenient way to modify this in the future.
    fn eq(&self, other: &Blake2bHash) -> bool { crate::crypto::secure_eq(self, other) }
}

impl Eq for Blake2bHash {}

impl fmt::Display for Blake2bHash {
    /// Displays a Blake2bHash as a lowercase hex-encoded string.
    ///
    /// Due to historical precedent, the lowercasing *is* significant,
    /// as we sign the lowercase hex-encoded version of a Blake2b
    /// hash, and not simply the Blake2b hash itself, when we sign a
    /// HART file.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // hex::encode currently outputs lowercase strings, but we
        // want to strictly enforce this and guard against any future
        // changes to that crate.
        hex::encode(self).to_lowercase().fmt(f)
    }
}

impl FromStr for Blake2bHash {
    type Err = Error;

    /// Convert a hex-encoded byte string into a Blake2bHash. Ensures
    /// the string represents a byte array of proper length.
    ///
    /// Case of the incoming string is not significant (e.g.,
    /// "DEADBEEF" and "deadbeef" are equivalent).
    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        // FromHex has an implementation for [u8; 32], so this ensures
        // the proper length of bytes... well, that and the compiler,
        // of course :)
        FromHex::from_hex(s).map(Self).map_err(|e| {
                                          Error::CryptoError(format!("Could not parse \
                                                                      Blake2bHash from string: {}",
                                                                     e))
                                      })
    }
}

////////////////////////////////////////////////////////////////////////

/// Calculate the BLAKE2b hash of a file, return as a hex string
/// digest size = 32 BYTES
/// NOTE: the hashing is keyless
pub fn hash_file<P>(filename: P) -> Result<String>
    where P: AsRef<Path>
{
    let file = File::open(filename.as_ref())?;
    let mut reader = BufReader::new(file);
    hash_reader(&mut reader)
}

pub fn hash_string(data: &str) -> String {
    let mut out = [0u8; HASH_DIGEST_SIZE];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    #[allow(clippy::cast_ptr_alignment)]
    let pst = st.as_mut_ptr() as *mut libsodium_sys::crypto_generichash_state;
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    hex::encode(out)
}

pub fn hash_bytes(data: &[u8]) -> String {
    let mut out = [0u8; HASH_DIGEST_SIZE];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    #[allow(clippy::cast_ptr_alignment)]
    let pst = st.as_mut_ptr() as *mut libsodium_sys::crypto_generichash_state;
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    hex::encode(out)
}

pub fn hash_reader(reader: &mut dyn Read) -> Result<String> {
    let mut out = [0u8; HASH_DIGEST_SIZE];
    let mut st = vec![0u8; unsafe { libsodium_sys::crypto_generichash_statebytes() }];
    #[allow(clippy::cast_ptr_alignment)]
    let pst = st.as_mut_ptr() as *mut libsodium_sys::crypto_generichash_state;
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
    }
    let mut buf = [0u8; BUF_SIZE];
    loop {
        let bytes_read = reader.read(&mut buf)?;
        if bytes_read == 0 {
            break;
        }
        let chunk = &buf[0..bytes_read];
        unsafe {
            libsodium_sys::crypto_generichash_update(pst, chunk.as_ptr(), chunk.len() as u64);
        }
    }
    unsafe {
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    Ok(hex::encode(out))
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use std::fs::{self,
                  File};
    #[allow(unused_imports)]
    use std::io;
    use std::{env,
              path::PathBuf};

    use super::{super::test_support::*,
                *};
    #[cfg(feature = "functional")]
    use hyper::{header,
                Client,
                Url};

    #[allow(dead_code)]
    fn mk_local_tmpdir() -> PathBuf {
        let dir = env::current_exe().unwrap()
                                    .parent()
                                    .unwrap()
                                    .parent()
                                    .unwrap()
                                    .parent()
                                    .unwrap()
                                    .parent()
                                    .unwrap()
                                    .parent()
                                    .unwrap()
                                    .join("tmp");
        fs::create_dir_all(&dir).unwrap();
        dir
    }

    #[test]
    fn hash_file_working() {
        // The expected values were computed using the `b2sum` program from
        // https://github.com/dchest/b2sum using the the `-s=32` option. For example:
        //      b2sum -s=32 signme.dat

        let computed = hash_file(&fixture("signme.dat")).unwrap();
        let expected = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.sig.key")).unwrap();
        let expected = "e966844bbc50b7a3a6d81e94dd38e27b92814b944095a8e55f1780921bfcfbe1";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.pub")).unwrap();
        let expected = "b80c4f412f9a0a7727b6e6f115e1b5fa3bae79ad2fcf47f769ed4e42cfb12265";
        assert_eq!(computed, expected);
    }

    #[test]
    #[cfg(feature = "functional")]
    fn hash_file_large_binary() {
        let url = "http://ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.3.tar.gz";
        let dst: PathBuf = {
            let file = mk_local_tmpdir().join(url.rsplit('/').next().unwrap());
            if !file.is_file() {
                let client = match env::var("http_proxy") {
                    Ok(url) => {
                        let url = Url::parse(&url).unwrap();
                        Client::with_http_proxy(url.host_str().unwrap().to_string(),
                                                url.port_or_known_default().unwrap())
                    }
                    _ => Client::new(),
                };
                let mut response = client.get(url)
                                         .header(header::Connection::close())
                                         .send()
                                         .unwrap();
                let mut f = File::create(&file).unwrap();
                io::copy(&mut response, &mut f).unwrap();
            }
            file
        };
        let computed = hash_file(&dst);
        let expected = "ba640dc063f0ed27e60b38dbb7cf19778cf7805d9fc91eb129fb68b409d46414";
        assert_eq!(computed, expected);
    }

    mod blake2bhash {
        use super::*;

        #[test]
        fn eq() {
            let zeroes = Blake2bHash([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                      0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                      0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]);

            let ones = Blake2bHash([1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                    1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                    1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]);

            assert_ne!(zeroes, ones);
            assert_eq!(zeroes, zeroes);
            assert_eq!(ones, ones);
        }

        #[test]
        fn display() {
            let ones = Blake2bHash([1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                    1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                    1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]);
            assert_eq!(ones.to_string(),
                       "0101010101010101010101010101010101010101010101010101010101010101");
        }

        #[test]
        fn from_str_good() {
            // Exactly 32 bytes long
            let h = "0101010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_ok());
        }

        #[test]
        fn from_str_short() {
            // This is one byte too short
            let h = "01010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_err());
        }
        #[test]
        fn from_str_long() {
            // This is one byte too long
            let h = "010101010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_err());
        }

        #[test]
        fn from_str_case_is_insignificant() {
            let lower_case = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
            let upper_case = "20590A52C4F00588C500328B16D466C982A26FABAA5FA4DCC83052DD0A84F233";

            let l = lower_case.parse::<Blake2bHash>().unwrap();
            let u = upper_case.parse::<Blake2bHash>().unwrap();

            assert_eq!(l, u);
        }

        #[test]
        fn from_str_display_round_trip() {
            let input = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
            let output = input.parse::<Blake2bHash>().unwrap().to_string();
            assert_eq!(output, input);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>add blockgroup element<commit_after><|endoftext|>


<commit_before><commit_msg>only declare libc crate when needed<commit_after><|endoftext|>


<commit_before><commit_msg>Complete initial reader -> writer upgrade implementation.<commit_after><|endoftext|>


<commit_before><commit_msg>archive: fix parse_self for upcoming 1.22<commit_after><|endoftext|>


<commit_before>use snake;
use game_state;

pub static NUMBER_OF_LAYERS: uint = 4;
pub static WATER_COLOR: [f32, ..4] = [0.0, 0.0, 0.45, 1.0];
pub static WATER_FRICTION: f64 = 0.2;
pub static RADIUS: f64 = 0.1;
pub static SURFACE_Y: f64 = 0.8;
pub static INITIAL_GAME_STATE: game_state::GameState = game_state::Play;
pub static INITIAL_CAMERA_POS: [f64, ..2] = [0.0, 0.0];
pub static CAMERA_FOLLOW_PERCENTAGE: f64 = 0.2;

pub static YOU_WIN_TEXT: &'static str = "you win";
pub static YOU_WIN_TEXT_COLOR: [f32, ..4] = GREEN;
pub static YOU_WIN_POS: [f64, ..2] = [-0.42, 0.1];

pub static YOU_LOOSE_TEXT: &'static str = "you loose";
pub static YOU_LOOSE_TEXT_COLOR: [f32, ..4] = RED;
pub static YOU_LOOSE_POS: [f64, ..2] = [-0.55, 0.1];

pub static PLAYER_LOOSE_AIR_SPEED: f64 = 0.1;
pub static PLAYER_COLOR: [f32, ..4] = YELLOW;
pub static PLAYER_INITIAL_BLOOD: f64 = 1.0;
pub static PLAYER_INITIAL_AIR: f64 = 1.0;
pub static PLAYER_RADIUS: f64 = 0.1;
pub static PLAYER_ACCELERATION_RIGHT: f64 = 0.1;
pub static PLAYER_ACCELERATION_LEFT: f64 = 0.1;
pub static PLAYER_ACCELERATION_UP: f64 = 0.1;
pub static PLAYER_ACCELERATION_DOWN: f64 = 0.1;
pub static PLAYER_INITIAL_TWEEN_FACTOR: f64 = 0.0;
pub static PLAYER_TWEEN_SPEED: f64 = 1.0;

pub struct SnakeSettings {
    pub acceleration_left: f64,
    pub acceleration_right: f64,
    pub acceleration_up: f64,
    pub acceleration_down: f64,
    pub initial_state: snake::SnakeState,
    pub bite_damage: f64,
    pub sensor_distance: f64,
    pub attack_distance: f64,
    pub wait_seconds_before_initial_attack: f64,
    pub wait_seconds_before_repeat_attack: f64,
    pub test_color: [f32, ..4],
    pub radius: f64,
}

pub static SNAKE_TAIL_COLOR: [f32, ..4] = [0.8, 0.6, 0.6, 0.4];

pub static SNAKE_TAIL_DISTANCE: f64 = 0.01;
pub static SNAKE_OVERALL_ACCELERATION: f64 = 2.0;
pub static SNAKE_SETTINGS: SnakeSettings = SnakeSettings {
    acceleration_left: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_right: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_up: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_down: 0.1 * SNAKE_OVERALL_ACCELERATION,
    initial_state: snake::Ignorant,
    bite_damage: 0.1,
    sensor_distance: 0.2,
    attack_distance: 2.0 * PLAYER_RADIUS,
    wait_seconds_before_initial_attack: 1.0,
    wait_seconds_before_repeat_attack: 1.0,
    test_color: BLACK,
    radius: 0.03,
};

pub static SNAKE_SPEED_RIGHT: f64 = 0.1;
pub static SNAKE_SPEED_LEFT: f64 = 0.1;
pub static SNAKE_SPEED_UP: f64 = 0.1;
pub static SNAKE_SPEED_DOWN: f64 = 0.1;

// snake 1.
pub static SNAKE_1_SETTINGS: SnakeSettings = SNAKE_SETTINGS;
pub static SNAKE_1_POS: [f64, ..2] = [-0.8, 0.8];
pub static SNAKE_1_ADD: bool = true;

// snake 2.
pub static SNAKE_2_SETTINGS: SnakeSettings = SNAKE_SETTINGS;
pub static SNAKE_2_POS: [f64, ..2] = [0.8, 0.8];
pub static SNAKE_2_ADD: bool = true;

pub static BAR_RECTANGLE: [f64, ..4] = [0.3, -0.06, 1.5, 0.05];
pub static BAR_MARGIN: f64 = 0.01;
pub static BAR_TEXT_COLOR: [f32, ..4] = WHITE;

pub static AIR_BAR_INITIAL_VALUE: f64 = 0.5;
pub static AIR_BAR_POS: [f64, ..2] = [-0.9, 0.95];
pub static AIR_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static AIR_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_BLUE;
pub static AIR_BAR_BAR_COLOR: [f32, ..4] = LIGHT_BLUE;

pub static BLOOD_BAR_INITIAL_VALUE: f64 = 0.5;
pub static BLOOD_BAR_POS: [f64, ..2] = [-0.9, 0.85];
pub static BLOOD_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static BLOOD_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_RED;
pub static BLOOD_BAR_BAR_COLOR: [f32, ..4] = LIGHT_RED;

pub static BAR_BACKGROUND_HEIGHT: f64 = 0.275;
pub static BAR_BACKGROUND_COLOR: [f32, ..4] = [0.1, 0.1, 0.1, 0.9];
pub static BAR_BACKGROUND_COLOR_2: [f32, ..4] = [0.4, 0.4, 0.4, 0.8];
pub static BAR_BACKGROUND_MARGIN: f64 = 0.01;
pub static BAR_BACKGROUND_MARGIN_2: f64 = 0.02;

pub static BLACK: [f32, ..4] = [0.0, 0.0, 0.0, 1.0];
pub static WHITE: [f32, ..4] = [1.0, 1.0, 1.0, 1.0];
pub static GRAY: [f32, ..4] = [0.5, 0.5, 0.5, 1.0];
pub static DARK_GRAY: [f32, ..4] = [0.2, 0.2, 0.2, 1.0];

pub static RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];
pub static DARK_RED: [f32, ..4] = [0.5, 0.0, 0.0, 1.0];
pub static LIGHT_RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];

pub static GREEN: [f32, ..4] = [0.0, 1.0, 0.0, 1.0];

pub static BLUE: [f32, ..4] = [0.0, 0.0, 1.0, 1.0];
pub static DARK_BLUE: [f32, ..4] = [0.0, 0.0, 0.5, 1.0];
pub static LIGHT_BLUE: [f32, ..4] = [0.5, 0.5, 1.0, 1.0];

pub static YELLOW: [f32, ..4] = [0.0, 1.0, 1.0, 1.0];

pub static ORIGIN: [f64, ..2] = [0.0, 0.0];

<commit_msg>Increase snake sensor distance<commit_after>use snake;
use game_state;

pub static NUMBER_OF_LAYERS: uint = 4;
pub static WATER_COLOR: [f32, ..4] = [0.0, 0.0, 0.45, 1.0];
pub static WATER_FRICTION: f64 = 0.2;
pub static RADIUS: f64 = 0.1;
pub static SURFACE_Y: f64 = 0.8;
pub static INITIAL_GAME_STATE: game_state::GameState = game_state::Play;
pub static INITIAL_CAMERA_POS: [f64, ..2] = [0.0, 0.0];
pub static CAMERA_FOLLOW_PERCENTAGE: f64 = 0.2;

pub static YOU_WIN_TEXT: &'static str = "you win";
pub static YOU_WIN_TEXT_COLOR: [f32, ..4] = GREEN;
pub static YOU_WIN_POS: [f64, ..2] = [-0.42, 0.1];

pub static YOU_LOOSE_TEXT: &'static str = "you loose";
pub static YOU_LOOSE_TEXT_COLOR: [f32, ..4] = RED;
pub static YOU_LOOSE_POS: [f64, ..2] = [-0.55, 0.1];

pub static PLAYER_LOOSE_AIR_SPEED: f64 = 0.1;
pub static PLAYER_COLOR: [f32, ..4] = YELLOW;
pub static PLAYER_INITIAL_BLOOD: f64 = 1.0;
pub static PLAYER_INITIAL_AIR: f64 = 1.0;
pub static PLAYER_RADIUS: f64 = 0.1;
pub static PLAYER_ACCELERATION_RIGHT: f64 = 0.1;
pub static PLAYER_ACCELERATION_LEFT: f64 = 0.1;
pub static PLAYER_ACCELERATION_UP: f64 = 0.1;
pub static PLAYER_ACCELERATION_DOWN: f64 = 0.1;
pub static PLAYER_INITIAL_TWEEN_FACTOR: f64 = 0.0;
pub static PLAYER_TWEEN_SPEED: f64 = 1.0;

pub struct SnakeSettings {
    pub acceleration_left: f64,
    pub acceleration_right: f64,
    pub acceleration_up: f64,
    pub acceleration_down: f64,
    pub initial_state: snake::SnakeState,
    pub bite_damage: f64,
    pub sensor_distance: f64,
    pub attack_distance: f64,
    pub wait_seconds_before_initial_attack: f64,
    pub wait_seconds_before_repeat_attack: f64,
    pub test_color: [f32, ..4],
    pub radius: f64,
}

pub static SNAKE_TAIL_COLOR: [f32, ..4] = [0.8, 0.6, 0.6, 0.4];

pub static SNAKE_TAIL_DISTANCE: f64 = 0.01;
pub static SNAKE_OVERALL_ACCELERATION: f64 = 2.0;
pub static SNAKE_SETTINGS: SnakeSettings = SnakeSettings {
    acceleration_left: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_right: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_up: 0.1 * SNAKE_OVERALL_ACCELERATION,
    acceleration_down: 0.1 * SNAKE_OVERALL_ACCELERATION,
    initial_state: snake::Ignorant,
    bite_damage: 0.1,
    sensor_distance: 2.0,
    attack_distance: 2.0 * PLAYER_RADIUS,
    wait_seconds_before_initial_attack: 1.0,
    wait_seconds_before_repeat_attack: 1.0,
    test_color: BLACK,
    radius: 0.03,
};

pub static SNAKE_SPEED_RIGHT: f64 = 0.1;
pub static SNAKE_SPEED_LEFT: f64 = 0.1;
pub static SNAKE_SPEED_UP: f64 = 0.1;
pub static SNAKE_SPEED_DOWN: f64 = 0.1;

// snake 1.
pub static SNAKE_1_SETTINGS: SnakeSettings = SNAKE_SETTINGS;
pub static SNAKE_1_POS: [f64, ..2] = [-0.8, 0.8];
pub static SNAKE_1_ADD: bool = true;

// snake 2.
pub static SNAKE_2_SETTINGS: SnakeSettings = SNAKE_SETTINGS;
pub static SNAKE_2_POS: [f64, ..2] = [0.8, 0.8];
pub static SNAKE_2_ADD: bool = true;

pub static BAR_RECTANGLE: [f64, ..4] = [0.3, -0.06, 1.5, 0.05];
pub static BAR_MARGIN: f64 = 0.01;
pub static BAR_TEXT_COLOR: [f32, ..4] = WHITE;

pub static AIR_BAR_INITIAL_VALUE: f64 = 0.5;
pub static AIR_BAR_POS: [f64, ..2] = [-0.9, 0.95];
pub static AIR_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static AIR_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_BLUE;
pub static AIR_BAR_BAR_COLOR: [f32, ..4] = LIGHT_BLUE;

pub static BLOOD_BAR_INITIAL_VALUE: f64 = 0.5;
pub static BLOOD_BAR_POS: [f64, ..2] = [-0.9, 0.85];
pub static BLOOD_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static BLOOD_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_RED;
pub static BLOOD_BAR_BAR_COLOR: [f32, ..4] = LIGHT_RED;

pub static BAR_BACKGROUND_HEIGHT: f64 = 0.275;
pub static BAR_BACKGROUND_COLOR: [f32, ..4] = [0.1, 0.1, 0.1, 0.9];
pub static BAR_BACKGROUND_COLOR_2: [f32, ..4] = [0.4, 0.4, 0.4, 0.8];
pub static BAR_BACKGROUND_MARGIN: f64 = 0.01;
pub static BAR_BACKGROUND_MARGIN_2: f64 = 0.02;

pub static BLACK: [f32, ..4] = [0.0, 0.0, 0.0, 1.0];
pub static WHITE: [f32, ..4] = [1.0, 1.0, 1.0, 1.0];
pub static GRAY: [f32, ..4] = [0.5, 0.5, 0.5, 1.0];
pub static DARK_GRAY: [f32, ..4] = [0.2, 0.2, 0.2, 1.0];

pub static RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];
pub static DARK_RED: [f32, ..4] = [0.5, 0.0, 0.0, 1.0];
pub static LIGHT_RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];

pub static GREEN: [f32, ..4] = [0.0, 1.0, 0.0, 1.0];

pub static BLUE: [f32, ..4] = [0.0, 0.0, 1.0, 1.0];
pub static DARK_BLUE: [f32, ..4] = [0.0, 0.0, 0.5, 1.0];
pub static LIGHT_BLUE: [f32, ..4] = [0.5, 0.5, 1.0, 1.0];

pub static YELLOW: [f32, ..4] = [0.0, 1.0, 1.0, 1.0];

pub static ORIGIN: [f64, ..2] = [0.0, 0.0];

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::{create_dir_all, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use config::Config;
use log::info;
use serde_derive::{Deserialize, Serialize};
use shellexpand::tilde;

use crate::error::Error;
use crate::platform::directories::*;

/// All settings which are used by both, the client and the daemon
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct Shared {
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The directory that is used for all runtime information. \
    /// I.e. task logs, sockets, state dumps, etc.
    pub pueue_directory: PathBuf,
    /// If this is set to true, unix sockets will be used.
    /// Otherwise we default to TCP+TLS
    #[cfg(not(target_os = "windows"))]
    pub use_unix_socket: bool,
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The path to the unix socket.
    #[cfg(not(target_os = "windows"))]
    pub unix_socket_path: PathBuf,

    /// The TCP hostname/ip address.
    pub host: String,
    /// The TCP port.
    pub port: String,
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The path to the TLS certificate used by the daemon. \
    /// This is also used by the client to verify the daemon's identity.
    pub daemon_cert: PathBuf,
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The path to the TLS key used by the daemon.
    pub daemon_key: PathBuf,
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The path to the file containing the shared secret used to authenticate the client.
    pub shared_secret_path: PathBuf,
}

/// All settings which are used by the client
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct Client {
    /// If set to true, all tasks will be restart in place, instead of creating a new task.
    /// False is the default, as you'll lose the logs of the previously failed tasks when
    /// restarting tasks in place.
    pub restart_in_place: bool,
    /// Whether the client should read the logs directly from disk or whether it should
    /// request the data from the daemon via socket.
    pub read_local_logs: bool,
    /// Whether the client should show a confirmation question on potential dangerous actions.
    pub show_confirmation_questions: bool,
    /// Whether aliases specified in `pueue_aliases.yml` should be expanded in the `pueue status`
    /// or shown in their short form.
    pub show_expanded_aliases: bool,
    /// Whether the client should use dark shades instead of regular colors.
    pub dark_mode: bool,
    /// The max amount of lines each task get's in the `pueue status` view.
    pub max_status_lines: Option<usize>,
    /// The format that will be used to display time formats in `pueue status`.
    pub status_time_format: String,
    /// The format that will be used to display datetime formats in `pueue status`.
    pub status_datetime_format: String,
}

/// All settings which are used by the daemon
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct Daemon {
    /// Whether a group should be paused as soon as a single task fails
    pub pause_group_on_failure: bool,
    /// Whether the daemon (and all groups) should be paused as soon as a single task fails
    pub pause_all_on_failure: bool,
    /// The callback that's called whenever a task finishes.
    pub callback: Option<String>,
    /// The amount of log lines from stdout/stderr that are passed to the callback command.
    pub callback_log_lines: usize,
    /// The legacy configuration for groups
    #[serde(skip_serializing)]
    #[deprecated(
        since = "1.1",
        note = "The configuration for groups is now stored in the state."
    )]
    pub groups: Option<HashMap<String, i64>>,
}

/// The parent settings struct. \
/// This contains all other setting structs.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct Settings {
    pub client: Client,
    pub daemon: Daemon,
    pub shared: Shared,
}

impl Shared {
    pub fn expand(old_path: &Path) -> PathBuf {
        PathBuf::from(tilde(&old_path.to_string_lossy()).into_owned())
    }

    pub fn pueue_directory(&self) -> PathBuf {
        Shared::expand(&self.pueue_directory)
    }

    #[cfg(not(target_os = "windows"))]
    pub fn unix_socket_path(&self) -> PathBuf {
        Shared::expand(&self.unix_socket_path)
    }

    pub fn daemon_cert(&self) -> PathBuf {
        Shared::expand(&self.daemon_cert)
    }
    pub fn daemon_key(&self) -> PathBuf {
        Shared::expand(&self.daemon_key)
    }
    pub fn shared_secret_path(&self) -> PathBuf {
        Shared::expand(&self.shared_secret_path)
    }
}

impl Settings {
    /// Read from existing config files.
    /// If no config files can be found or fields are missing, an error is returned.
    pub fn read(from_file: &Option<PathBuf>) -> Result<Settings, Error> {
        let config = Config::new();
        let (settings, _) = parse_config(config, from_file)?;

        Ok(settings)
    }

    /// Try to read existing config files, while using default values for non-existing fields.
    /// If successful, this will return a full config as well as a boolean on whether we found an
    /// existing configuration file or not.
    ///
    /// The default local config locations depends on the current target.
    pub fn read_with_defaults(from_file: &Option<PathBuf>) -> Result<(Settings, bool), Error> {
        let config = Settings::default_config()?;
        parse_config(config, from_file)
    }

    pub fn default_config() -> Result<Config, Error> {
        let mut config = Config::new();
        let pueue_path = default_pueue_path()?;
        config
            .set_default("shared.pueue_directory", pueue_path.clone())
            .unwrap();
        #[cfg(not(target_os = "windows"))]
        config.set_default("shared.use_unix_socket", true).unwrap();
        #[cfg(not(target_os = "windows"))]
        config
            .set_default("shared.unix_socket_path", get_unix_socket_path()?)
            .unwrap();

        config.set_default("shared.host", "127.0.0.1").unwrap();
        config.set_default("shared.port", "6924").unwrap();
        config.set_default("shared.tls_enabled", true).unwrap();
        config
            .set_default(
                "shared.daemon_key",
                pueue_path.clone() + "/certs/daemon.key",
            )
            .unwrap();
        config
            .set_default(
                "shared.daemon_cert",
                pueue_path.clone() + "/certs/daemon.cert",
            )
            .unwrap();
        config
            .set_default("shared.shared_secret_path", pueue_path + "/shared_secret")
            .unwrap();

        // Client specific config
        config
            .set_default("client.restart_in_place", false)
            .unwrap();
        config.set_default("client.read_local_logs", true).unwrap();
        config
            .set_default("client.show_expanded_aliases", false)
            .unwrap();
        config
            .set_default("client.show_confirmation_questions", false)
            .unwrap();
        config.set_default("client.dark_mode", false).unwrap();
        config
            .set_default("client.max_status_lines", None::<i64>)
            .unwrap();
        config
            .set_default("client.newline_between_date_and_time", false)
            .unwrap();
        config
            .set_default("client.status_time_format", "%H:%M:%S".to_string())
            .unwrap();
        config
            .set_default(
                "client.status_datetime_format",
                "%Y-%m-%d\n%H:%M:%S".to_string(),
            )
            .unwrap();

        // Daemon specific config
        config
            .set_default("daemon.default_parallel_tasks", 1)
            .unwrap();
        config
            .set_default("daemon.pause_group_on_failure", false)
            .unwrap();
        config
            .set_default("daemon.pause_all_on_failure", false)
            .unwrap();
        config
            .set_default("daemon.callback", None::<String>)
            .unwrap();
        config.set_default("daemon.callback_log_lines", 10).unwrap();
        config
            .set_default("daemon.groups", None::<HashMap<String, i64>>)
            .unwrap();

        Ok(config)
    }

    /// Save the current configuration as a file to the given path. \
    /// If no path is given, the default configuration path will be used. \
    /// The file is then written to the main configuration directory of the respective OS.
    pub fn save(&self, path: &Option<PathBuf>) -> Result<(), Error> {
        let config_path = if let Some(path) = path {
            path.clone()
        } else {
            default_config_directory()?.join("pueue.yml")
        };
        let config_dir = config_path
            .parent()
            .ok_or_else(|| Error::InvalidPath("Couldn't resolve config directory".into()))?;

        // Create the config dir, if it doesn't exist yet
        if !config_dir.exists() {
            create_dir_all(config_dir)?;
        }

        let content = match serde_yaml::to_string(self) {
            Ok(content) => content,
            Err(error) => {
                return Err(Error::Generic(format!(
                    "Configuration file serialization failed:\n{}",
                    error
                )))
            }
        };
        let mut file = File::create(config_path)?;
        file.write_all(content.as_bytes())?;

        Ok(())
    }
}

/// Get all possible configuration paths and check if there are
/// configuration files at those locations.
/// All configs will be merged by importance.
fn parse_config(
    mut config: Config,
    from_file: &Option<PathBuf>,
) -> Result<(Settings, bool), Error> {
    // Load the config from a very specific file path
    if let Some(path) = from_file {
        if !path.exists() || !path.is_file() {
            return Err(Error::FileNotFound(format!(
                "Couldn't find config at path {:?}",
                path
            )));
        }
        info!("Using config file at: {:?}", path);
        let config_file = config::File::with_name(path.to_str().unwrap());
        config.merge(config_file)?;
        return Ok((config.try_into()?, true));
    };

    let mut config_found = false;
    info!("Parsing config files");
    for directory in get_config_directories()?.into_iter() {
        let path = directory.join("pueue.yml");
        info!("Checking path: {:?}", &path);

        // Check if the file exists and parse it.
        if path.exists() && path.is_file() {
            info!("Found config file at: {:?}", path);
            config_found = true;
            let config_file = config::File::with_name(path.to_str().unwrap());
            config.merge(config_file)?;
        }
    }

    // Try to can deserialize the entire configuration
    Ok((config.try_into()?, config_found))
}
<commit_msg>fix: Semver value in deprecation decorator<commit_after>use std::collections::HashMap;
use std::fs::{create_dir_all, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use config::Config;
use log::info;
use serde_derive::{Deserialize, Serialize};
use shellexpand::tilde;

use crate::error::Error;
use crate::platform::directories::*;

/// All settings which are used by both, the client and the daemon
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct Shared {
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The directory that is used for all runtime information. \
    /// I.e. task logs, sockets, state dumps, etc.
    pub pueue_directory: PathBuf,
    /// If this is set to true, unix sockets will be used.
    /// Otherwise we default to TCP+TLS
    #[cfg(not(target_os = "windows"))]
    pub use_unix_socket: bool,
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The path to the unix socket.
    #[cfg(not(target_os = "windows"))]
    pub unix_socket_path: PathBuf,

    /// The TCP hostname/ip address.
    pub host: String,
    /// The TCP port.
    pub port: String,
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The path to the TLS certificate used by the daemon. \
    /// This is also used by the client to verify the daemon's identity.
    pub daemon_cert: PathBuf,
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The path to the TLS key used by the daemon.
    pub daemon_key: PathBuf,
    /// Don't access this property directly, but rather use the getter with the same name.
    /// It's only public to allow proper integration testing.
    ///
    /// The path to the file containing the shared secret used to authenticate the client.
    pub shared_secret_path: PathBuf,
}

/// All settings which are used by the client
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct Client {
    /// If set to true, all tasks will be restart in place, instead of creating a new task.
    /// False is the default, as you'll lose the logs of the previously failed tasks when
    /// restarting tasks in place.
    pub restart_in_place: bool,
    /// Whether the client should read the logs directly from disk or whether it should
    /// request the data from the daemon via socket.
    pub read_local_logs: bool,
    /// Whether the client should show a confirmation question on potential dangerous actions.
    pub show_confirmation_questions: bool,
    /// Whether aliases specified in `pueue_aliases.yml` should be expanded in the `pueue status`
    /// or shown in their short form.
    pub show_expanded_aliases: bool,
    /// Whether the client should use dark shades instead of regular colors.
    pub dark_mode: bool,
    /// The max amount of lines each task get's in the `pueue status` view.
    pub max_status_lines: Option<usize>,
    /// The format that will be used to display time formats in `pueue status`.
    pub status_time_format: String,
    /// The format that will be used to display datetime formats in `pueue status`.
    pub status_datetime_format: String,
}

/// All settings which are used by the daemon
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct Daemon {
    /// Whether a group should be paused as soon as a single task fails
    pub pause_group_on_failure: bool,
    /// Whether the daemon (and all groups) should be paused as soon as a single task fails
    pub pause_all_on_failure: bool,
    /// The callback that's called whenever a task finishes.
    pub callback: Option<String>,
    /// The amount of log lines from stdout/stderr that are passed to the callback command.
    pub callback_log_lines: usize,
    /// The legacy configuration for groups
    #[serde(skip_serializing)]
    #[deprecated(
        since = "1.1.0",
        note = "The configuration for groups is now stored in the state."
    )]
    pub groups: Option<HashMap<String, i64>>,
}

/// The parent settings struct. \
/// This contains all other setting structs.
#[derive(PartialEq, Clone, Debug, Deserialize, Serialize)]
pub struct Settings {
    pub client: Client,
    pub daemon: Daemon,
    pub shared: Shared,
}

impl Shared {
    pub fn expand(old_path: &Path) -> PathBuf {
        PathBuf::from(tilde(&old_path.to_string_lossy()).into_owned())
    }

    pub fn pueue_directory(&self) -> PathBuf {
        Shared::expand(&self.pueue_directory)
    }

    #[cfg(not(target_os = "windows"))]
    pub fn unix_socket_path(&self) -> PathBuf {
        Shared::expand(&self.unix_socket_path)
    }

    pub fn daemon_cert(&self) -> PathBuf {
        Shared::expand(&self.daemon_cert)
    }
    pub fn daemon_key(&self) -> PathBuf {
        Shared::expand(&self.daemon_key)
    }
    pub fn shared_secret_path(&self) -> PathBuf {
        Shared::expand(&self.shared_secret_path)
    }
}

impl Settings {
    /// Read from existing config files.
    /// If no config files can be found or fields are missing, an error is returned.
    pub fn read(from_file: &Option<PathBuf>) -> Result<Settings, Error> {
        let config = Config::new();
        let (settings, _) = parse_config(config, from_file)?;

        Ok(settings)
    }

    /// Try to read existing config files, while using default values for non-existing fields.
    /// If successful, this will return a full config as well as a boolean on whether we found an
    /// existing configuration file or not.
    ///
    /// The default local config locations depends on the current target.
    pub fn read_with_defaults(from_file: &Option<PathBuf>) -> Result<(Settings, bool), Error> {
        let config = Settings::default_config()?;
        parse_config(config, from_file)
    }

    pub fn default_config() -> Result<Config, Error> {
        let mut config = Config::new();
        let pueue_path = default_pueue_path()?;
        config
            .set_default("shared.pueue_directory", pueue_path.clone())
            .unwrap();
        #[cfg(not(target_os = "windows"))]
        config.set_default("shared.use_unix_socket", true).unwrap();
        #[cfg(not(target_os = "windows"))]
        config
            .set_default("shared.unix_socket_path", get_unix_socket_path()?)
            .unwrap();

        config.set_default("shared.host", "127.0.0.1").unwrap();
        config.set_default("shared.port", "6924").unwrap();
        config.set_default("shared.tls_enabled", true).unwrap();
        config
            .set_default(
                "shared.daemon_key",
                pueue_path.clone() + "/certs/daemon.key",
            )
            .unwrap();
        config
            .set_default(
                "shared.daemon_cert",
                pueue_path.clone() + "/certs/daemon.cert",
            )
            .unwrap();
        config
            .set_default("shared.shared_secret_path", pueue_path + "/shared_secret")
            .unwrap();

        // Client specific config
        config
            .set_default("client.restart_in_place", false)
            .unwrap();
        config.set_default("client.read_local_logs", true).unwrap();
        config
            .set_default("client.show_expanded_aliases", false)
            .unwrap();
        config
            .set_default("client.show_confirmation_questions", false)
            .unwrap();
        config.set_default("client.dark_mode", false).unwrap();
        config
            .set_default("client.max_status_lines", None::<i64>)
            .unwrap();
        config
            .set_default("client.newline_between_date_and_time", false)
            .unwrap();
        config
            .set_default("client.status_time_format", "%H:%M:%S".to_string())
            .unwrap();
        config
            .set_default(
                "client.status_datetime_format",
                "%Y-%m-%d\n%H:%M:%S".to_string(),
            )
            .unwrap();

        // Daemon specific config
        config
            .set_default("daemon.default_parallel_tasks", 1)
            .unwrap();
        config
            .set_default("daemon.pause_group_on_failure", false)
            .unwrap();
        config
            .set_default("daemon.pause_all_on_failure", false)
            .unwrap();
        config
            .set_default("daemon.callback", None::<String>)
            .unwrap();
        config.set_default("daemon.callback_log_lines", 10).unwrap();
        config
            .set_default("daemon.groups", None::<HashMap<String, i64>>)
            .unwrap();

        Ok(config)
    }

    /// Save the current configuration as a file to the given path. \
    /// If no path is given, the default configuration path will be used. \
    /// The file is then written to the main configuration directory of the respective OS.
    pub fn save(&self, path: &Option<PathBuf>) -> Result<(), Error> {
        let config_path = if let Some(path) = path {
            path.clone()
        } else {
            default_config_directory()?.join("pueue.yml")
        };
        let config_dir = config_path
            .parent()
            .ok_or_else(|| Error::InvalidPath("Couldn't resolve config directory".into()))?;

        // Create the config dir, if it doesn't exist yet
        if !config_dir.exists() {
            create_dir_all(config_dir)?;
        }

        let content = match serde_yaml::to_string(self) {
            Ok(content) => content,
            Err(error) => {
                return Err(Error::Generic(format!(
                    "Configuration file serialization failed:\n{}",
                    error
                )))
            }
        };
        let mut file = File::create(config_path)?;
        file.write_all(content.as_bytes())?;

        Ok(())
    }
}

/// Get all possible configuration paths and check if there are
/// configuration files at those locations.
/// All configs will be merged by importance.
fn parse_config(
    mut config: Config,
    from_file: &Option<PathBuf>,
) -> Result<(Settings, bool), Error> {
    // Load the config from a very specific file path
    if let Some(path) = from_file {
        if !path.exists() || !path.is_file() {
            return Err(Error::FileNotFound(format!(
                "Couldn't find config at path {:?}",
                path
            )));
        }
        info!("Using config file at: {:?}", path);
        let config_file = config::File::with_name(path.to_str().unwrap());
        config.merge(config_file)?;
        return Ok((config.try_into()?, true));
    };

    let mut config_found = false;
    info!("Parsing config files");
    for directory in get_config_directories()?.into_iter() {
        let path = directory.join("pueue.yml");
        info!("Checking path: {:?}", &path);

        // Check if the file exists and parse it.
        if path.exists() && path.is_file() {
            info!("Found config file at: {:?}", path);
            config_found = true;
            let config_file = config::File::with_name(path.to_str().unwrap());
            config.merge(config_file)?;
        }
    }

    // Try to can deserialize the entire configuration
    Ok((config.try_into()?, config_found))
}
<|endoftext|>


<commit_before>use crate::utils::{
    add_extra_ty_param_bound, add_extra_where_clauses, field_idents, get_field_types, named_to_vec,
    unnamed_to_vec,
};
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{Data, DeriveInput, Field, Fields, Ident};

pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream {
    let trait_ident = Ident::new(trait_name, Span::call_site());
    let method_name = trait_name.to_string().to_lowercase();
    let method_ident = Ident::new(&(method_name.to_string()), Span::call_site());
    let input_type = &input.ident;
    let trait_path = quote!(::core::iter::#trait_ident);
    let op_trait_name = if trait_name == "Sum" {
        "Add"
    } else {
        "Mul"
    };
    let op_trait_ident = Ident::new(op_trait_name, Span::call_site());
    let op_path = quote!(::core::ops::#op_trait_ident);
    let op_method_ident = Ident::new(&(op_trait_name.to_string().to_lowercase()), Span::call_site());
    let type_params: Vec<_> = input
        .generics
        .type_params()
        .map(|t| t.ident.clone())
        .collect();
    let generics = if type_params.len() > 0 {
        let generic_type = quote!(<#(#type_params),*>);
        let generics = add_extra_ty_param_bound(&input.generics, &trait_path);
        let operator_where_clause = quote! {
            where #input_type#generic_type: #op_path<Output=#input_type#generic_type>
        };
        add_extra_where_clauses(&generics, operator_where_clause)
    } else {
        input.generics.clone()
    };
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let identity = match input.data {
        Data::Struct(ref data_struct) => match data_struct.fields {
            Fields::Unnamed(ref fields) => {
                tuple_identity(input_type, &unnamed_to_vec(fields), &method_ident)
            }
            Fields::Named(ref fields) => {
                struct_identity(input_type, &named_to_vec(fields), &method_ident)
            }
            _ => panic!(format!("Unit structs cannot use derive({})", trait_name)),
        },

        _ => panic!(format!("Only structs can use derive({})", trait_name)),
    };

    quote!(
        impl#impl_generics #trait_path for #input_type#ty_generics #where_clause {
            #[inline]
            fn #method_ident<I: ::core::iter::Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(#identity, #op_path::#op_method_ident)
            }
        }
    )
}

fn tuple_identity<T: ToTokens>(
    input_type: &T,
    fields: &[&Field],
    method_ident: &Ident,
) -> TokenStream {
    let types = &get_field_types(fields);
    quote!(#input_type(#(::core::iter::empty::<#types>().#method_ident()),*))
}

fn struct_identity(input_type: &Ident, fields: &[&Field], method_ident: &Ident) -> TokenStream {
    let field_names = field_idents(fields);
    let types = &get_field_types(fields);

    quote!(#input_type{#(#field_names: ::core::iter::empty::<#types>().#method_ident()),*})
}
<commit_msg>Fix clippy<commit_after>use crate::utils::{
    add_extra_ty_param_bound, add_extra_where_clauses, field_idents, get_field_types, named_to_vec,
    unnamed_to_vec,
};
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{Data, DeriveInput, Field, Fields, Ident};

pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream {
    let trait_ident = Ident::new(trait_name, Span::call_site());
    let method_name = trait_name.to_string().to_lowercase();
    let method_ident = Ident::new(&(method_name.to_string()), Span::call_site());
    let input_type = &input.ident;
    let trait_path = quote!(::core::iter::#trait_ident);
    let op_trait_name = if trait_name == "Sum" {
        "Add"
    } else {
        "Mul"
    };
    let op_trait_ident = Ident::new(op_trait_name, Span::call_site());
    let op_path = quote!(::core::ops::#op_trait_ident);
    let op_method_ident = Ident::new(&(op_trait_name.to_string().to_lowercase()), Span::call_site());
    let type_params: Vec<_> = input
        .generics
        .type_params()
        .map(|t| t.ident.clone())
        .collect();
    let generics = if type_params.is_empty() {
        input.generics.clone()
    } else {
        let generic_type = quote!(<#(#type_params),*>);
        let generics = add_extra_ty_param_bound(&input.generics, &trait_path);
        let operator_where_clause = quote! {
            where #input_type#generic_type: #op_path<Output=#input_type#generic_type>
        };
        add_extra_where_clauses(&generics, operator_where_clause)
    };
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let identity = match input.data {
        Data::Struct(ref data_struct) => match data_struct.fields {
            Fields::Unnamed(ref fields) => {
                tuple_identity(input_type, &unnamed_to_vec(fields), &method_ident)
            }
            Fields::Named(ref fields) => {
                struct_identity(input_type, &named_to_vec(fields), &method_ident)
            }
            _ => panic!(format!("Unit structs cannot use derive({})", trait_name)),
        },

        _ => panic!(format!("Only structs can use derive({})", trait_name)),
    };

    quote!(
        impl#impl_generics #trait_path for #input_type#ty_generics #where_clause {
            #[inline]
            fn #method_ident<I: ::core::iter::Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(#identity, #op_path::#op_method_ident)
            }
        }
    )
}

fn tuple_identity<T: ToTokens>(
    input_type: &T,
    fields: &[&Field],
    method_ident: &Ident,
) -> TokenStream {
    let types = &get_field_types(fields);
    quote!(#input_type(#(::core::iter::empty::<#types>().#method_ident()),*))
}

fn struct_identity(input_type: &Ident, fields: &[&Field], method_ident: &Ident) -> TokenStream {
    let field_names = field_idents(fields);
    let types = &get_field_types(fields);

    quote!(#input_type{#(#field_names: ::core::iter::empty::<#types>().#method_ident()),*})
}
<|endoftext|>


<commit_before>#![cfg(test)]

use std::collections::HashMap;
use rustc_serialize::json;
use rustc_serialize::json::{Json, Object};
use rustc_serialize::{Decoder, Decodable};
use std::io::prelude::*;
use std::fs::File;
use token::{Token, ReservedWord};

pub struct ExpectPass {
    source: String,
    expected: Json,
    options: Option<Json>
}

pub struct ExpectFail {
    source: String,
    error: String,
    options: Option<Json>
}

pub enum TestCase {
    Pass(ExpectPass),
    Fail(ExpectFail)
}

trait JsonExt {
    fn into_array(self) -> json::Array;
    fn into_string(self) -> String;
    fn into_string_opt(self) -> Option<String>;
}

impl JsonExt for Json {
    fn into_array(self) -> json::Array {
        match self {
            Json::Array(array) => array,
            _ => panic!("expected array")
        }
    }
    fn into_string(self) -> String {
        match self {
            Json::String(string) => string,
            _ => panic!("expected string")
        }
    }
    fn into_string_opt(self) -> Option<String> {
        match self {
            Json::Null => None,
            Json::String(string) => Some(string),
            _ => panic!("expected string or null")
        }
    }
}

fn parse_expect_fail(test: &mut Object) -> ExpectFail {
    ExpectFail {
        source: test.remove("source").unwrap().into_string(),
        error: test.remove("error").unwrap().into_string(),
        options: None
    }
}

fn parse_expect_pass(test: &mut Object) -> ExpectPass {
    ExpectPass {
        source: test.remove("source").unwrap().into_string(),
        expected: test.remove("expected").unwrap(),
        options: None
    }
}

fn deserialize_reserved(word: &str) -> ReservedWord {
    match word {
        "Null"       => ReservedWord::Null,
        "True"       => ReservedWord::True,
        "False"      => ReservedWord::False,
        "Arguments"  => ReservedWord::Arguments,
        "Eval"       => ReservedWord::Eval,
        "Break"      => ReservedWord::Break,
        "Case"       => ReservedWord::Case,
        "Catch"      => ReservedWord::Catch,
        "Class"      => ReservedWord::Class,
        "Const"      => ReservedWord::Const,
        "Continue"   => ReservedWord::Continue,
        "Debugger"   => ReservedWord::Debugger,
        "Default"    => ReservedWord::Default,
        "Delete"     => ReservedWord::Delete,
        "Do"         => ReservedWord::Do,
        "Else"       => ReservedWord::Else,
        "Export"     => ReservedWord::Export,
        "Extends"    => ReservedWord::Extends,
        "Finally"    => ReservedWord::Finally,
        "For"        => ReservedWord::For,
        "Function"   => ReservedWord::Function,
        "If"         => ReservedWord::If,
        "Import"     => ReservedWord::Import,
        "In"         => ReservedWord::In,
        "Instanceof" => ReservedWord::Instanceof,
        "Let"        => ReservedWord::Let,
        "New"        => ReservedWord::New,
        "Return"     => ReservedWord::Return,
        "Static"     => ReservedWord::Static,
        "Super"      => ReservedWord::Super,
        "Switch"     => ReservedWord::Switch,
        "This"       => ReservedWord::This,
        "Throw"      => ReservedWord::Throw,
        "Try"        => ReservedWord::Try,
        "Typeof"     => ReservedWord::Typeof,
        "Var"        => ReservedWord::Var,
        "Void"       => ReservedWord::Void,
        "While"      => ReservedWord::While,
        "With"       => ReservedWord::With,
        "Yield"      => ReservedWord::Yield,
        "Enum"       => ReservedWord::Enum,
        "Await"      => ReservedWord::Await,
        "Implements" => ReservedWord::Implements,
        "Interface"  => ReservedWord::Interface,
        "Package"    => ReservedWord::Package,
        "Private"    => ReservedWord::Private,
        "Protected"  => ReservedWord::Protected,
        "Public"     => ReservedWord::Public,
        _            => panic!("invalid reserved word")
    }
}

macro_rules! right {
    ( $l:expr, $r:expr ) => { $r }
}

macro_rules! tuplify {
    ( $v:expr, ( $($dummy:tt),* ) ) => {
        {
            let mut t = $v.into_iter();
            ($(
                right!($dummy, t.next().unwrap())
            ),*)
        }
    };
}

fn deserialize_token(mut data: Json) -> Token {
    let mut arr = data.into_array();
    let ty = arr.remove(0).into_string();

    match &ty[..] {
        "Reserved"      => {
            let s = arr.remove(0).into_string();
            Token::Reserved(deserialize_reserved(&s[..]))
        }
        "LBrace"        => Token::LBrace,
        "RBrace"        => Token::RBrace,
        "LParen"        => Token::LParen,
        "RParen"        => Token::RParen,
        "LBrack"        => Token::LBrack,
        "RBrack"        => Token::RBrack,
        "Dot"           => Token::Dot,
        //"Ellipsis"    => Token::Ellipsis,
        "Semi"          => Token::Semi,
        "Comma"         => Token::Comma,
        "LAngle"        => Token::LAngle,
        "RAngle"        => Token::RAngle,
        "LEq"           => Token::LEq,
        "GEq"           => Token::GEq,
        "Eq"            => Token::Eq,
        "NEq"           => Token::NEq,
        "StrictEq"      => Token::StrictEq,
        "StrictNEq"     => Token::StrictNEq,
        "Plus"          => Token::Plus,
        "Minus"         => Token::Minus,
        "Star"          => Token::Star,
        "Mod"           => Token::Mod,
        "Slash"         => Token::Slash,
        "Inc"           => Token::Inc,
        "Dec"           => Token::Dec,
        "LShift"        => Token::LShift,
        "RShift"        => Token::RShift,
        "URShift"       => Token::URShift,
        "BitAnd"        => Token::BitAnd,
        "BitOr"         => Token::BitOr,
        "BitXor"        => Token::BitXor,
        "Bang"          => Token::Bang,
        "Tilde"         => Token::Tilde,
        "LogicalAnd"    => Token::LogicalAnd,
        "LogicalOr"     => Token::LogicalOr,
        "Question"      => Token::Question,
        "Colon"         => Token::Colon,
        "Assign"        => Token::Assign,
        "PlusAssign"    => Token::PlusAssign,
        "MinusAssign"   => Token::MinusAssign,
        "StarAssign"    => Token::StarAssign,
        "SlashAssign"   => Token::SlashAssign,
        "ModAssign"     => Token::ModAssign,
        "LShiftAssign"  => Token::LShiftAssign,
        "RShiftAssign"  => Token::RShiftAssign,
        "URShiftAssign" => Token::URShiftAssign,
        "BitAndAssign"  => Token::BitAndAssign,
        "BitOrAssign"   => Token::BitOrAssign,
        "BitXorAssign"  => Token::BitXorAssign,
        "Arrow"         => Token::Arrow,
        "Newline"       => Token::Newline,
        "EOF"           => Token::EOF,
        "DecimalInt"    => Token::DecimalInt(arr.remove(0).into_string()),
        "BinaryInt"     => {
            let (flag, value) = tuplify!(arr, (_, _));
            Token::BinaryInt(flag.into_string().remove(0), value.into_string())
        }
        "OctalInt"      => {
            let flag = arr.remove(0).into_string_opt().map(|mut str| str.remove(0));
            Token::OctalInt(flag, arr.remove(0).into_string())
        }
        "HexInt"        => {
            let flag = arr.remove(0).into_string().remove(0);
            Token::HexInt(flag, arr.remove(0).into_string())
        }
        "Float"         => {
            let int = arr.remove(0).into_string_opt();
            let frac = arr.remove(0).into_string_opt();
            let exp = arr.remove(0).into_string_opt();
            Token::Float(int, frac, exp)
        }
        "String"        => Token::String(arr.remove(0).into_string()),
        "RegExp"        => Token::RegExp(arr.remove(0).into_string()),
        "Identifier"    => Token::Identifier(arr.remove(0).into_string()),
        "LineComment"   => Token::LineComment(arr.remove(0).into_string()),
        "BlockComment"  => Token::BlockComment(arr.remove(0).into_string()),
        _               => panic!("invalid token")
    }
}

fn parse_test(mut test: Json) -> TestCase {
    let obj = test.as_object_mut().unwrap();
    if obj.contains_key("error") {
        TestCase::Fail(parse_expect_fail(obj))
    } else {
        TestCase::Pass(parse_expect_pass(obj))
    }
}

pub fn parse_tests(src: &str) -> Vec<TestCase> {
    let t = Json::from_str("[\"DecimalInt\",\"11.3\"]").unwrap();
    println!("yo: {:?}", deserialize_token(t));
    let data: Json = src.parse().unwrap();
    data.into_array()
        .into_iter()
        .map(parse_test)
        .collect()
}
<commit_msg>OK, I can get the macro working with () as the dummy syntax instead of _ -- I can live with that<commit_after>#![cfg(test)]

use std::collections::HashMap;
use rustc_serialize::json;
use rustc_serialize::json::{Json, Object};
use rustc_serialize::{Decoder, Decodable};
use std::io::prelude::*;
use std::fs::File;
use token::{Token, ReservedWord};

pub struct ExpectPass {
    source: String,
    expected: Json,
    options: Option<Json>
}

pub struct ExpectFail {
    source: String,
    error: String,
    options: Option<Json>
}

pub enum TestCase {
    Pass(ExpectPass),
    Fail(ExpectFail)
}

trait JsonExt {
    fn into_array(self) -> json::Array;
    fn into_string(self) -> String;
    fn into_string_opt(self) -> Option<String>;
}

impl JsonExt for Json {
    fn into_array(self) -> json::Array {
        match self {
            Json::Array(array) => array,
            _ => panic!("expected array")
        }
    }
    fn into_string(self) -> String {
        match self {
            Json::String(string) => string,
            _ => panic!("expected string")
        }
    }
    fn into_string_opt(self) -> Option<String> {
        match self {
            Json::Null => None,
            Json::String(string) => Some(string),
            _ => panic!("expected string or null")
        }
    }
}

fn parse_expect_fail(test: &mut Object) -> ExpectFail {
    ExpectFail {
        source: test.remove("source").unwrap().into_string(),
        error: test.remove("error").unwrap().into_string(),
        options: None
    }
}

fn parse_expect_pass(test: &mut Object) -> ExpectPass {
    ExpectPass {
        source: test.remove("source").unwrap().into_string(),
        expected: test.remove("expected").unwrap(),
        options: None
    }
}

fn deserialize_reserved(word: &str) -> ReservedWord {
    match word {
        "Null"       => ReservedWord::Null,
        "True"       => ReservedWord::True,
        "False"      => ReservedWord::False,
        "Arguments"  => ReservedWord::Arguments,
        "Eval"       => ReservedWord::Eval,
        "Break"      => ReservedWord::Break,
        "Case"       => ReservedWord::Case,
        "Catch"      => ReservedWord::Catch,
        "Class"      => ReservedWord::Class,
        "Const"      => ReservedWord::Const,
        "Continue"   => ReservedWord::Continue,
        "Debugger"   => ReservedWord::Debugger,
        "Default"    => ReservedWord::Default,
        "Delete"     => ReservedWord::Delete,
        "Do"         => ReservedWord::Do,
        "Else"       => ReservedWord::Else,
        "Export"     => ReservedWord::Export,
        "Extends"    => ReservedWord::Extends,
        "Finally"    => ReservedWord::Finally,
        "For"        => ReservedWord::For,
        "Function"   => ReservedWord::Function,
        "If"         => ReservedWord::If,
        "Import"     => ReservedWord::Import,
        "In"         => ReservedWord::In,
        "Instanceof" => ReservedWord::Instanceof,
        "Let"        => ReservedWord::Let,
        "New"        => ReservedWord::New,
        "Return"     => ReservedWord::Return,
        "Static"     => ReservedWord::Static,
        "Super"      => ReservedWord::Super,
        "Switch"     => ReservedWord::Switch,
        "This"       => ReservedWord::This,
        "Throw"      => ReservedWord::Throw,
        "Try"        => ReservedWord::Try,
        "Typeof"     => ReservedWord::Typeof,
        "Var"        => ReservedWord::Var,
        "Void"       => ReservedWord::Void,
        "While"      => ReservedWord::While,
        "With"       => ReservedWord::With,
        "Yield"      => ReservedWord::Yield,
        "Enum"       => ReservedWord::Enum,
        "Await"      => ReservedWord::Await,
        "Implements" => ReservedWord::Implements,
        "Interface"  => ReservedWord::Interface,
        "Package"    => ReservedWord::Package,
        "Private"    => ReservedWord::Private,
        "Protected"  => ReservedWord::Protected,
        "Public"     => ReservedWord::Public,
        _            => panic!("invalid reserved word")
    }
}

macro_rules! right {
    ( $l:expr, $r:expr ) => { $r }
}

macro_rules! tuplify {
    ( $v:expr, ( $($dummy:tt),* ) ) => {
        {
            let mut t = $v.into_iter();
            ($(
                right!($dummy, t.next().unwrap())
            ),*)
        }
    };
}

fn deserialize_token(mut data: Json) -> Token {
    let mut arr = data.into_array();
    let ty = arr.remove(0).into_string();

    match &ty[..] {
        "Reserved"      => {
            let s = arr.remove(0).into_string();
            Token::Reserved(deserialize_reserved(&s[..]))
        }
        "LBrace"        => Token::LBrace,
        "RBrace"        => Token::RBrace,
        "LParen"        => Token::LParen,
        "RParen"        => Token::RParen,
        "LBrack"        => Token::LBrack,
        "RBrack"        => Token::RBrack,
        "Dot"           => Token::Dot,
        //"Ellipsis"    => Token::Ellipsis,
        "Semi"          => Token::Semi,
        "Comma"         => Token::Comma,
        "LAngle"        => Token::LAngle,
        "RAngle"        => Token::RAngle,
        "LEq"           => Token::LEq,
        "GEq"           => Token::GEq,
        "Eq"            => Token::Eq,
        "NEq"           => Token::NEq,
        "StrictEq"      => Token::StrictEq,
        "StrictNEq"     => Token::StrictNEq,
        "Plus"          => Token::Plus,
        "Minus"         => Token::Minus,
        "Star"          => Token::Star,
        "Mod"           => Token::Mod,
        "Slash"         => Token::Slash,
        "Inc"           => Token::Inc,
        "Dec"           => Token::Dec,
        "LShift"        => Token::LShift,
        "RShift"        => Token::RShift,
        "URShift"       => Token::URShift,
        "BitAnd"        => Token::BitAnd,
        "BitOr"         => Token::BitOr,
        "BitXor"        => Token::BitXor,
        "Bang"          => Token::Bang,
        "Tilde"         => Token::Tilde,
        "LogicalAnd"    => Token::LogicalAnd,
        "LogicalOr"     => Token::LogicalOr,
        "Question"      => Token::Question,
        "Colon"         => Token::Colon,
        "Assign"        => Token::Assign,
        "PlusAssign"    => Token::PlusAssign,
        "MinusAssign"   => Token::MinusAssign,
        "StarAssign"    => Token::StarAssign,
        "SlashAssign"   => Token::SlashAssign,
        "ModAssign"     => Token::ModAssign,
        "LShiftAssign"  => Token::LShiftAssign,
        "RShiftAssign"  => Token::RShiftAssign,
        "URShiftAssign" => Token::URShiftAssign,
        "BitAndAssign"  => Token::BitAndAssign,
        "BitOrAssign"   => Token::BitOrAssign,
        "BitXorAssign"  => Token::BitXorAssign,
        "Arrow"         => Token::Arrow,
        "Newline"       => Token::Newline,
        "EOF"           => Token::EOF,
        "DecimalInt"    => Token::DecimalInt(arr.remove(0).into_string()),
        "BinaryInt"     => {
            let (flag, value) = tuplify!(arr, ((), ()));
            Token::BinaryInt(flag.into_string().remove(0), value.into_string())
        }
        "OctalInt"      => {
            let (flag, value) = tuplify!(arr, ((), ()));
            Token::OctalInt(flag.into_string_opt().map(|mut str| str.remove(0)),
                            value.into_string())
        }
        "HexInt"        => {
            let (flag, value) = tuplify!(arr, ((), ()));
            Token::HexInt(flag.into_string().remove(0), value.into_string())
        }
        "Float"         => {
            let (int, frac, exp) = tuplify!(arr, ((), (), ()));
            Token::Float(int.into_string_opt(), frac.into_string_opt(), exp.into_string_opt())
        }
        "String"        => Token::String(arr.remove(0).into_string()),
        "RegExp"        => Token::RegExp(arr.remove(0).into_string()),
        "Identifier"    => Token::Identifier(arr.remove(0).into_string()),
        "LineComment"   => Token::LineComment(arr.remove(0).into_string()),
        "BlockComment"  => Token::BlockComment(arr.remove(0).into_string()),
        _               => panic!("invalid token")
    }
}

fn parse_test(mut test: Json) -> TestCase {
    let obj = test.as_object_mut().unwrap();
    if obj.contains_key("error") {
        TestCase::Fail(parse_expect_fail(obj))
    } else {
        TestCase::Pass(parse_expect_pass(obj))
    }
}

pub fn parse_tests(src: &str) -> Vec<TestCase> {
    let t = Json::from_str("[\"DecimalInt\",\"11.3\"]").unwrap();
    println!("yo: {:?}", deserialize_token(t));
    let data: Json = src.parse().unwrap();
    data.into_array()
        .into_iter()
        .map(parse_test)
        .collect()
}
<|endoftext|>


<commit_before>use crate::syntax::atom::Atom::*;
use crate::syntax::{
    Array, Atom, Derive, Enum, ExternFn, ExternType, Impl, Lifetimes, NamedType, Receiver, Ref,
    Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var,
};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote_spanned, ToTokens};
use syn::{token, Token};

impl ToTokens for Type {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            Type::Ident(ident) => {
                if ident.rust == Char {
                    let span = ident.rust.span();
                    tokens.extend(quote_spanned!(span=> ::std::os::raw::));
                } else if ident.rust == CxxString {
                    let span = ident.rust.span();
                    tokens.extend(quote_spanned!(span=> ::cxx::));
                }
                ident.to_tokens(tokens);
            }
            Type::RustBox(ty)
            | Type::UniquePtr(ty)
            | Type::SharedPtr(ty)
            | Type::WeakPtr(ty)
            | Type::CxxVector(ty)
            | Type::RustVec(ty) => ty.to_tokens(tokens),
            Type::Ref(r) | Type::Str(r) => r.to_tokens(tokens),
            Type::Array(a) => a.to_tokens(tokens),
            Type::Fn(f) => f.to_tokens(tokens),
            Type::Void(span) => tokens.extend(quote_spanned!(*span=> ())),
            Type::SliceRef(r) => r.to_tokens(tokens),
        }
    }
}

impl ToTokens for Var {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Var {
            doc: _,
            attrs: _,
            visibility: _,
            name,
            ty,
        } = self;
        name.rust.to_tokens(tokens);
        Token![:](name.rust.span()).to_tokens(tokens);
        ty.to_tokens(tokens);
    }
}

impl ToTokens for Ty1 {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Ty1 {
            name,
            langle,
            inner,
            rangle,
        } = self;
        let span = name.span();
        match name.to_string().as_str() {
            "UniquePtr" | "SharedPtr" | "WeakPtr" | "CxxVector" => {
                tokens.extend(quote_spanned!(span=> ::cxx::));
            }
            "Vec" => {
                tokens.extend(quote_spanned!(span=> ::std::vec::));
            }
            _ => {}
        }
        name.to_tokens(tokens);
        langle.to_tokens(tokens);
        inner.to_tokens(tokens);
        rangle.to_tokens(tokens);
    }
}

impl ToTokens for Ref {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Ref {
            pinned: _,
            ampersand,
            lifetime,
            mutable: _,
            inner,
            pin_tokens,
            mutability,
        } = self;
        if let Some((pin, langle, _rangle)) = pin_tokens {
            tokens.extend(quote_spanned!(pin.span=> ::std::pin::Pin));
            langle.to_tokens(tokens);
        }
        ampersand.to_tokens(tokens);
        lifetime.to_tokens(tokens);
        mutability.to_tokens(tokens);
        inner.to_tokens(tokens);
        if let Some((_pin, _langle, rangle)) = pin_tokens {
            rangle.to_tokens(tokens);
        }
    }
}

impl ToTokens for SliceRef {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let SliceRef {
            ampersand,
            lifetime,
            mutable: _,
            bracket,
            inner,
            mutability,
        } = self;
        ampersand.to_tokens(tokens);
        lifetime.to_tokens(tokens);
        mutability.to_tokens(tokens);
        bracket.surround(tokens, |tokens| {
            inner.to_tokens(tokens);
        });
    }
}

impl ToTokens for Array {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Array {
            bracket,
            inner,
            semi_token,
            len: _,
            len_token,
        } = self;
        bracket.surround(tokens, |tokens| {
            inner.to_tokens(tokens);
            semi_token.to_tokens(tokens);
            len_token.to_tokens(tokens);
        });
    }
}

impl ToTokens for Atom {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        Ident::new(self.as_ref(), Span::call_site()).to_tokens(tokens);
    }
}

impl ToTokens for Derive {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        Ident::new(self.what.as_ref(), self.span).to_tokens(tokens);
    }
}

impl ToTokens for ExternType {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.type_token.to_tokens(tokens);
        self.name.rust.to_tokens(tokens);
    }
}

impl ToTokens for TypeAlias {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.type_token.to_tokens(tokens);
        self.name.rust.to_tokens(tokens);
    }
}

impl ToTokens for Struct {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.struct_token.to_tokens(tokens);
        self.name.rust.to_tokens(tokens);
    }
}

impl ToTokens for Enum {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.enum_token.to_tokens(tokens);
        self.name.rust.to_tokens(tokens);
    }
}

impl ToTokens for ExternFn {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.sig.fn_token.to_tokens(tokens);
        self.semi_token.to_tokens(tokens);
    }
}

impl ToTokens for Impl {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Impl {
            impl_token,
            impl_generics,
            negative: _,
            ty,
            ty_generics: _,
            brace_token,
            negative_token,
        } = self;
        impl_token.to_tokens(tokens);
        impl_generics.to_tokens(tokens);
        negative_token.to_tokens(tokens);
        ty.to_tokens(tokens);
        brace_token.surround(tokens, |_tokens| {});
    }
}

impl ToTokens for Lifetimes {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Lifetimes {
            lt_token,
            lifetimes,
            gt_token,
        } = self;
        lt_token.to_tokens(tokens);
        lifetimes.to_tokens(tokens);
        gt_token.to_tokens(tokens);
    }
}

impl ToTokens for Signature {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Signature {
            unsafety: _,
            fn_token,
            generics: _,
            receiver: _,
            args,
            ret,
            throws: _,
            paren_token,
            throws_tokens,
        } = self;
        fn_token.to_tokens(tokens);
        paren_token.surround(tokens, |tokens| {
            args.to_tokens(tokens);
        });
        if let Some(ret) = ret {
            Token![->](paren_token.span).to_tokens(tokens);
            if let Some((result, langle, rangle)) = throws_tokens {
                result.to_tokens(tokens);
                langle.to_tokens(tokens);
                ret.to_tokens(tokens);
                rangle.to_tokens(tokens);
            } else {
                ret.to_tokens(tokens);
            }
        } else if let Some((result, langle, rangle)) = throws_tokens {
            Token![->](paren_token.span).to_tokens(tokens);
            result.to_tokens(tokens);
            langle.to_tokens(tokens);
            token::Paren(langle.span).surround(tokens, |_| ());
            rangle.to_tokens(tokens);
        }
    }
}

impl ToTokens for NamedType {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let NamedType { rust, generics } = self;
        rust.to_tokens(tokens);
        generics.to_tokens(tokens);
    }
}

pub struct ReceiverType<'a>(&'a Receiver);

impl Receiver {
    // &TheType
    pub fn ty(&self) -> ReceiverType {
        ReceiverType(self)
    }
}

impl ToTokens for ReceiverType<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Receiver {
            pinned: _,
            ampersand,
            lifetime,
            mutable: _,
            var: _,
            ty,
            shorthand: _,
            pin_tokens,
            mutability,
        } = &self.0;
        if let Some((pin, langle, _rangle)) = pin_tokens {
            tokens.extend(quote_spanned!(pin.span=> ::std::pin::Pin));
            langle.to_tokens(tokens);
        }
        ampersand.to_tokens(tokens);
        lifetime.to_tokens(tokens);
        mutability.to_tokens(tokens);
        ty.to_tokens(tokens);
        if let Some((_pin, _langle, rangle)) = pin_tokens {
            rangle.to_tokens(tokens);
        }
    }
}
<commit_msg>Include lifetimes in error reporting spans<commit_after>use crate::syntax::atom::Atom::*;
use crate::syntax::{
    Array, Atom, Derive, Enum, ExternFn, ExternType, Impl, Lifetimes, NamedType, Receiver, Ref,
    Signature, SliceRef, Struct, Ty1, Type, TypeAlias, Var,
};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote_spanned, ToTokens};
use syn::{token, Token};

impl ToTokens for Type {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            Type::Ident(ident) => {
                if ident.rust == Char {
                    let span = ident.rust.span();
                    tokens.extend(quote_spanned!(span=> ::std::os::raw::));
                } else if ident.rust == CxxString {
                    let span = ident.rust.span();
                    tokens.extend(quote_spanned!(span=> ::cxx::));
                }
                ident.to_tokens(tokens);
            }
            Type::RustBox(ty)
            | Type::UniquePtr(ty)
            | Type::SharedPtr(ty)
            | Type::WeakPtr(ty)
            | Type::CxxVector(ty)
            | Type::RustVec(ty) => ty.to_tokens(tokens),
            Type::Ref(r) | Type::Str(r) => r.to_tokens(tokens),
            Type::Array(a) => a.to_tokens(tokens),
            Type::Fn(f) => f.to_tokens(tokens),
            Type::Void(span) => tokens.extend(quote_spanned!(*span=> ())),
            Type::SliceRef(r) => r.to_tokens(tokens),
        }
    }
}

impl ToTokens for Var {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Var {
            doc: _,
            attrs: _,
            visibility: _,
            name,
            ty,
        } = self;
        name.rust.to_tokens(tokens);
        Token![:](name.rust.span()).to_tokens(tokens);
        ty.to_tokens(tokens);
    }
}

impl ToTokens for Ty1 {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Ty1 {
            name,
            langle,
            inner,
            rangle,
        } = self;
        let span = name.span();
        match name.to_string().as_str() {
            "UniquePtr" | "SharedPtr" | "WeakPtr" | "CxxVector" => {
                tokens.extend(quote_spanned!(span=> ::cxx::));
            }
            "Vec" => {
                tokens.extend(quote_spanned!(span=> ::std::vec::));
            }
            _ => {}
        }
        name.to_tokens(tokens);
        langle.to_tokens(tokens);
        inner.to_tokens(tokens);
        rangle.to_tokens(tokens);
    }
}

impl ToTokens for Ref {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Ref {
            pinned: _,
            ampersand,
            lifetime,
            mutable: _,
            inner,
            pin_tokens,
            mutability,
        } = self;
        if let Some((pin, langle, _rangle)) = pin_tokens {
            tokens.extend(quote_spanned!(pin.span=> ::std::pin::Pin));
            langle.to_tokens(tokens);
        }
        ampersand.to_tokens(tokens);
        lifetime.to_tokens(tokens);
        mutability.to_tokens(tokens);
        inner.to_tokens(tokens);
        if let Some((_pin, _langle, rangle)) = pin_tokens {
            rangle.to_tokens(tokens);
        }
    }
}

impl ToTokens for SliceRef {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let SliceRef {
            ampersand,
            lifetime,
            mutable: _,
            bracket,
            inner,
            mutability,
        } = self;
        ampersand.to_tokens(tokens);
        lifetime.to_tokens(tokens);
        mutability.to_tokens(tokens);
        bracket.surround(tokens, |tokens| {
            inner.to_tokens(tokens);
        });
    }
}

impl ToTokens for Array {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Array {
            bracket,
            inner,
            semi_token,
            len: _,
            len_token,
        } = self;
        bracket.surround(tokens, |tokens| {
            inner.to_tokens(tokens);
            semi_token.to_tokens(tokens);
            len_token.to_tokens(tokens);
        });
    }
}

impl ToTokens for Atom {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        Ident::new(self.as_ref(), Span::call_site()).to_tokens(tokens);
    }
}

impl ToTokens for Derive {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        Ident::new(self.what.as_ref(), self.span).to_tokens(tokens);
    }
}

impl ToTokens for ExternType {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.type_token.to_tokens(tokens);
        self.name.rust.to_tokens(tokens);
        self.generics.to_tokens(tokens);
    }
}

impl ToTokens for TypeAlias {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.type_token.to_tokens(tokens);
        self.name.rust.to_tokens(tokens);
        self.generics.to_tokens(tokens);
    }
}

impl ToTokens for Struct {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.struct_token.to_tokens(tokens);
        self.name.rust.to_tokens(tokens);
        self.generics.to_tokens(tokens);
    }
}

impl ToTokens for Enum {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.enum_token.to_tokens(tokens);
        self.name.rust.to_tokens(tokens);
        self.generics.to_tokens(tokens);
    }
}

impl ToTokens for ExternFn {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        // Notional token range for error reporting purposes.
        self.sig.fn_token.to_tokens(tokens);
        self.semi_token.to_tokens(tokens);
    }
}

impl ToTokens for Impl {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Impl {
            impl_token,
            impl_generics,
            negative: _,
            ty,
            ty_generics: _,
            brace_token,
            negative_token,
        } = self;
        impl_token.to_tokens(tokens);
        impl_generics.to_tokens(tokens);
        negative_token.to_tokens(tokens);
        ty.to_tokens(tokens);
        brace_token.surround(tokens, |_tokens| {});
    }
}

impl ToTokens for Lifetimes {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Lifetimes {
            lt_token,
            lifetimes,
            gt_token,
        } = self;
        lt_token.to_tokens(tokens);
        lifetimes.to_tokens(tokens);
        gt_token.to_tokens(tokens);
    }
}

impl ToTokens for Signature {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Signature {
            unsafety: _,
            fn_token,
            generics: _,
            receiver: _,
            args,
            ret,
            throws: _,
            paren_token,
            throws_tokens,
        } = self;
        fn_token.to_tokens(tokens);
        paren_token.surround(tokens, |tokens| {
            args.to_tokens(tokens);
        });
        if let Some(ret) = ret {
            Token![->](paren_token.span).to_tokens(tokens);
            if let Some((result, langle, rangle)) = throws_tokens {
                result.to_tokens(tokens);
                langle.to_tokens(tokens);
                ret.to_tokens(tokens);
                rangle.to_tokens(tokens);
            } else {
                ret.to_tokens(tokens);
            }
        } else if let Some((result, langle, rangle)) = throws_tokens {
            Token![->](paren_token.span).to_tokens(tokens);
            result.to_tokens(tokens);
            langle.to_tokens(tokens);
            token::Paren(langle.span).surround(tokens, |_| ());
            rangle.to_tokens(tokens);
        }
    }
}

impl ToTokens for NamedType {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let NamedType { rust, generics } = self;
        rust.to_tokens(tokens);
        generics.to_tokens(tokens);
    }
}

pub struct ReceiverType<'a>(&'a Receiver);

impl Receiver {
    // &TheType
    pub fn ty(&self) -> ReceiverType {
        ReceiverType(self)
    }
}

impl ToTokens for ReceiverType<'_> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Receiver {
            pinned: _,
            ampersand,
            lifetime,
            mutable: _,
            var: _,
            ty,
            shorthand: _,
            pin_tokens,
            mutability,
        } = &self.0;
        if let Some((pin, langle, _rangle)) = pin_tokens {
            tokens.extend(quote_spanned!(pin.span=> ::std::pin::Pin));
            langle.to_tokens(tokens);
        }
        ampersand.to_tokens(tokens);
        lifetime.to_tokens(tokens);
        mutability.to_tokens(tokens);
        ty.to_tokens(tokens);
        if let Some((_pin, _langle, rangle)) = pin_tokens {
            rangle.to_tokens(tokens);
        }
    }
}
<|endoftext|>


<commit_before>//! A basic `Variable` implementation.
//!
//! Frontends can use any indexing scheme they see fit and
//! generate the appropriate `Variable` instances.
//!
//! Note: The `Variable` is used by Cranelift to index an array containing
//! information about your mutable variables. Thus, when you create a new
//! `Variable` you should make sure that the index is provided by a counter
//! incremented by 1 each time you encounter a new mutable variable.

use core::u32;
use cranelift_codegen::entity::EntityRef;

///! An opaque reference to a variable.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Variable(u32);

impl Variable {
    /// Create a new Variable with the given index.
    pub fn with_u32(index: u32) -> Self {
        debug_assert!(index < u32::MAX);
        Self(index)
    }
}

impl EntityRef for Variable {
    fn new(index: usize) -> Self {
        debug_assert!(index < (u32::MAX as usize));
        Self(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}
<commit_msg>Use less vague language<commit_after>//! A basic `Variable` implementation.
//!
//! Frontends can use any indexing scheme they see fit and
//! generate the appropriate `Variable` instances.
//!
//! Note: The `Variable` is used by Cranelift to index into densely allocated
//! arrays containing information about your mutable variables
//! Thus, make sure that Variable's indexes are allocated contiguously and
//! starting at `0`.

use core::u32;
use cranelift_codegen::entity::EntityRef;

///! An opaque reference to a variable.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Variable(u32);

impl Variable {
    /// Create a new Variable with the given index.
    pub fn with_u32(index: u32) -> Self {
        debug_assert!(index < u32::MAX);
        Self(index)
    }
}

impl EntityRef for Variable {
    fn new(index: usize) -> Self {
        debug_assert!(index < (u32::MAX as usize));
        Self(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}
<|endoftext|>