<commit_before>//! *lamport* implements one-time hash-based signatures using the Lamport signature scheme.

#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts,
        trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces,
        unused_qualifications)]

extern crate rand;
extern crate ring;

use rand::OsRng;
use rand::RngCore;
use ring::digest::{Algorithm, Context};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

/// A one-time signing public key
#[derive(Clone, Debug)]
pub struct PublicKey {
    zero_values: Vec<Vec<u8>>,
    one_values: Vec<Vec<u8>>,
    algorithm: &'static Algorithm,
}

impl PartialEq for PublicKey {
    #[allow(trivial_casts)]
    fn eq(&self, other: &Self) -> bool {
        self.algorithm as *const Algorithm == other.algorithm as *const Algorithm
            && self.zero_values == other.zero_values && self.one_values == other.one_values
    }
}

impl Eq for PublicKey {}

impl PartialOrd for PublicKey {
    fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for PublicKey {
    #[allow(trivial_casts)]
    fn cmp(&self, other: &PublicKey) -> Ordering {
        self.zero_values
            .cmp(&other.zero_values)
            .then(self.one_values.cmp(&other.one_values))
            .then((self.algorithm as *const Algorithm).cmp(&(other.algorithm as *const Algorithm)))
    }
}

impl Hash for PublicKey {
    #[allow(trivial_casts)]
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.zero_values.hash(state);
        self.one_values.hash(state);
        (self.algorithm as *const Algorithm).hash(state);
    }
}

/// A one-time signing private key
#[derive(Clone, Debug)]
pub struct PrivateKey {
    // For a n bits hash function: (n * n/8 bytes) for zero_values and one_values
    zero_values: Vec<Vec<u8>>,
    one_values: Vec<Vec<u8>>,
    algorithm: &'static Algorithm,
    used: bool,
}

impl From<PublicKey> for Vec<u8> {
    fn from(original: PublicKey) -> Vec<u8> {
        original.to_bytes()
    }
}

impl PublicKey {
    /// Intializes a public key with a byte vector.
    /// Returns `None` if it couldn't parse the provided data
    pub fn from_vec(vec: Vec<u8>, algorithm: &'static Algorithm) -> Option<PublicKey> {
        let size = vec.len();
        let hash_output_size = algorithm.output_len;
        if size != (hash_output_size * hash_output_size * 8 * 2) {
            return None;
        }

        let mut zero_values_merged = vec;
        let one_values_merged = zero_values_merged.split_off(size / 2);

        let mut zero_values = Vec::new();
        for i in (0..zero_values_merged.len()).filter(|x| x % hash_output_size == 0) {
            // indexes for heads
            let mut sub_vec = Vec::new();
            for j in 0..hash_output_size {
                sub_vec.push(zero_values_merged[i + j]);
            }

            zero_values.push(sub_vec);
        }

        let mut one_values = Vec::new();
        for i in (0..one_values_merged.len()).filter(|x| x % hash_output_size == 0) {
            // indexes for heads
            let mut sub_vec = Vec::new();
            for j in 0..hash_output_size {
                sub_vec.push(one_values_merged[i + j]);
            }

            one_values.push(sub_vec);
        }

        Some(PublicKey {
            zero_values,
            one_values,
            algorithm,
        })
    }

    /// Serializes a public key into a byte vector
    pub fn to_bytes(&self) -> Vec<u8> {
        self.zero_values
            .iter()
            .chain(self.one_values.iter())
            .fold(Vec::new(), |mut acc, i| {
                acc.append(&mut i.clone());
                acc
            })
    }

    /// Verifies that the signature of the data is correctly signed with the given key
    pub fn verify_signature(&self, signature: &[Vec<u8>], data: &[u8]) -> bool {
        if signature.len() != self.algorithm.output_len * 8 {
            return false;
        }

        let mut context = Context::new(self.algorithm);
        context.update(data);
        let result = context.finish();
        let data_hash = result.as_ref();

        for (i, byte) in data_hash.iter().enumerate() {
            for j in 0..8 {
                let offset = i * 8 + j;
                if (byte & (1 << j)) > 0 {
                    let mut context = Context::new(self.algorithm);
                    context.update(signature[offset].as_slice());
                    let hashed_value = Vec::from(context.finish().as_ref());

                    if hashed_value != self.one_values[offset] {
                        return false;
                    }
                } else {
                    let mut context = Context::new(self.algorithm);
                    context.update(signature[offset].as_slice());
                    let hashed_value = Vec::from(context.finish().as_ref());

                    if hashed_value != self.zero_values[offset] {
                        return false;
                    }
                }
            }
        }

        true
    }
}

impl PrivateKey {
    /// Generates a new random one-time signing key. This method can panic if OS RNG fails
    pub fn new(algorithm: &'static Algorithm) -> PrivateKey {
        let generate_bit_hash_values = || -> Vec<Vec<u8>> {
            let mut rng = match OsRng::new() {
                Ok(g) => g,
                Err(e) => panic!("Failed to obtain OS RNG: {}", e),
            };
            let buffer_byte = vec![0u8; algorithm.output_len];
            let mut buffer = vec![buffer_byte; algorithm.output_len * 8];

            for hash in &mut buffer {
                rng.fill_bytes(hash)
            }

            buffer
        };

        let zero_values = generate_bit_hash_values();
        let one_values = generate_bit_hash_values();

        PrivateKey {
            zero_values,
            one_values,
            algorithm,
            used: false,
        }
    }

    /// Returns the public key associated with this private key
    pub fn public_key(&self) -> PublicKey {
        let hash_values = |x: &Vec<Vec<u8>>| -> Vec<Vec<u8>> {
            let buffer_byte = vec![0u8; self.algorithm.output_len];
            let mut buffer = vec![buffer_byte; self.algorithm.output_len * 8];

            for i in 0..self.algorithm.output_len * 8 {
                let mut context = Context::new(self.algorithm);
                context.update(x[i].as_slice());
                buffer[i] = Vec::from(context.finish().as_ref());
            }

            buffer
        };

        let hashed_zero_values = hash_values(&self.zero_values);
        let hashed_one_values = hash_values(&self.one_values);

        PublicKey {
            zero_values: hashed_zero_values,
            one_values: hashed_one_values,
            algorithm: self.algorithm,
        }
    }

    /// Signs the data with the private key and returns the result if successful.
    /// If unsuccesful, an explanation string is returned
    pub fn sign(&mut self, data: &[u8]) -> Result<Vec<Vec<u8>>, &'static str> {
        if self.used {
            return Err("Attempting to sign more than once.");
        }

        let mut context = Context::new(self.algorithm);
        context.update(data);
        let result = context.finish();
        let data_hash = result.as_ref();

        let signature_len = data_hash.len() * 8;
        let mut signature = Vec::with_capacity(signature_len);

        for (i, byte) in data_hash.iter().enumerate() {
            for j in 0..8 {
                let offset = i * 8 + j;
                if (byte & (1 << j)) > 0 {
                    // Bit is 1
                    signature.push(self.one_values[offset].clone());
                } else {
                    // Bit is 0
                    signature.push(self.zero_values[offset].clone());
                }
            }
        }
        self.used = true;
        Ok(signature)
    }
}

impl Drop for PrivateKey {
    fn drop(&mut self) {
        let zeroize_vector = |vector: &mut Vec<Vec<u8>>| {
            for v2 in vector.iter_mut() {
                for byte in v2.iter_mut() {
                    *byte = 0;
                }
            }
        };

        zeroize_vector(&mut self.zero_values);
        zeroize_vector(&mut self.one_values);
    }
}

impl PartialEq for PrivateKey {
    // ⚠ This is not a constant-time implementation
    fn eq(&self, other: &PrivateKey) -> bool {
        if self.algorithm != other.algorithm {
            return false;
        }
        // NOTE: The `zero_values` and `one_values` need not be of the
        // the same length (and maybe this should change).
        let zero_size = self.zero_values.len();
        let one_size = self.one_values.len();
        if zero_size != other.zero_values.len() || one_size != other.one_values.len() {
            return false;
        }

        for i in 0..zero_size {
            if self.zero_values[i] != other.zero_values[i] {
                return false;
            }
        }
        for i in 0..one_size {
            if self.one_values[i] != other.one_values[i] {
                return false;
            }
        }
        true
    }
}

impl Eq for PrivateKey {}

impl PartialOrd for PrivateKey {
    fn partial_cmp(&self, other: &PrivateKey) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for PrivateKey {
    // ⚠ This is not a constant-time implementation
    fn cmp(&self, other: &PrivateKey) -> Ordering {
        self.one_values
            .cmp(&other.one_values)
            .then(self.zero_values.cmp(&other.zero_values))
    }
}

#[cfg(test)]
pub mod tests;
<commit_msg>Formatting<commit_after>//! *lamport* implements one-time hash-based signatures using the Lamport signature scheme.

#![deny(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

extern crate rand;
extern crate ring;

use rand::OsRng;
use rand::RngCore;
use ring::digest::{Algorithm, Context};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

/// A one-time signing public key
#[derive(Clone, Debug)]
pub struct PublicKey {
    zero_values: Vec<Vec<u8>>,
    one_values: Vec<Vec<u8>>,
    algorithm: &'static Algorithm,
}

impl PartialEq for PublicKey {
    #[allow(trivial_casts)]
    fn eq(&self, other: &Self) -> bool {
        self.algorithm as *const Algorithm == other.algorithm as *const Algorithm
            && self.zero_values == other.zero_values
            && self.one_values == other.one_values
    }
}

impl Eq for PublicKey {}

impl PartialOrd for PublicKey {
    fn partial_cmp(&self, other: &PublicKey) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for PublicKey {
    #[allow(trivial_casts)]
    fn cmp(&self, other: &PublicKey) -> Ordering {
        self.zero_values
            .cmp(&other.zero_values)
            .then(self.one_values.cmp(&other.one_values))
            .then((self.algorithm as *const Algorithm).cmp(&(other.algorithm as *const Algorithm)))
    }
}

impl Hash for PublicKey {
    #[allow(trivial_casts)]
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.zero_values.hash(state);
        self.one_values.hash(state);
        (self.algorithm as *const Algorithm).hash(state);
    }
}

/// A one-time signing private key
#[derive(Clone, Debug)]
pub struct PrivateKey {
    // For a n bits hash function: (n * n/8 bytes) for zero_values and one_values
    zero_values: Vec<Vec<u8>>,
    one_values: Vec<Vec<u8>>,
    algorithm: &'static Algorithm,
    used: bool,
}

impl From<PublicKey> for Vec<u8> {
    fn from(original: PublicKey) -> Vec<u8> {
        original.to_bytes()
    }
}

impl PublicKey {
    /// Intializes a public key with a byte vector.
    /// Returns `None` if it couldn't parse the provided data
    pub fn from_vec(vec: Vec<u8>, algorithm: &'static Algorithm) -> Option<PublicKey> {
        let size = vec.len();
        let hash_output_size = algorithm.output_len;
        if size != (hash_output_size * hash_output_size * 8 * 2) {
            return None;
        }

        let mut zero_values_merged = vec;
        let one_values_merged = zero_values_merged.split_off(size / 2);

        let mut zero_values = Vec::new();
        for i in (0..zero_values_merged.len()).filter(|x| x % hash_output_size == 0) {
            // indexes for heads
            let mut sub_vec = Vec::new();
            for j in 0..hash_output_size {
                sub_vec.push(zero_values_merged[i + j]);
            }

            zero_values.push(sub_vec);
        }

        let mut one_values = Vec::new();
        for i in (0..one_values_merged.len()).filter(|x| x % hash_output_size == 0) {
            // indexes for heads
            let mut sub_vec = Vec::new();
            for j in 0..hash_output_size {
                sub_vec.push(one_values_merged[i + j]);
            }

            one_values.push(sub_vec);
        }

        Some(PublicKey {
            zero_values,
            one_values,
            algorithm,
        })
    }

    /// Serializes a public key into a byte vector
    pub fn to_bytes(&self) -> Vec<u8> {
        self.zero_values
            .iter()
            .chain(self.one_values.iter())
            .fold(Vec::new(), |mut acc, i| {
                acc.append(&mut i.clone());
                acc
            })
    }

    /// Verifies that the signature of the data is correctly signed with the given key
    pub fn verify_signature(&self, signature: &[Vec<u8>], data: &[u8]) -> bool {
        if signature.len() != self.algorithm.output_len * 8 {
            return false;
        }

        let mut context = Context::new(self.algorithm);
        context.update(data);
        let result = context.finish();
        let data_hash = result.as_ref();

        for (i, byte) in data_hash.iter().enumerate() {
            for j in 0..8 {
                let offset = i * 8 + j;
                if (byte & (1 << j)) > 0 {
                    let mut context = Context::new(self.algorithm);
                    context.update(signature[offset].as_slice());
                    let hashed_value = Vec::from(context.finish().as_ref());

                    if hashed_value != self.one_values[offset] {
                        return false;
                    }
                } else {
                    let mut context = Context::new(self.algorithm);
                    context.update(signature[offset].as_slice());
                    let hashed_value = Vec::from(context.finish().as_ref());

                    if hashed_value != self.zero_values[offset] {
                        return false;
                    }
                }
            }
        }

        true
    }
}

impl PrivateKey {
    /// Generates a new random one-time signing key. This method can panic if OS RNG fails
    pub fn new(algorithm: &'static Algorithm) -> PrivateKey {
        let generate_bit_hash_values = || -> Vec<Vec<u8>> {
            let mut rng = match OsRng::new() {
                Ok(g) => g,
                Err(e) => panic!("Failed to obtain OS RNG: {}", e),
            };
            let buffer_byte = vec![0u8; algorithm.output_len];
            let mut buffer = vec![buffer_byte; algorithm.output_len * 8];

            for hash in &mut buffer {
                rng.fill_bytes(hash)
            }

            buffer
        };

        let zero_values = generate_bit_hash_values();
        let one_values = generate_bit_hash_values();

        PrivateKey {
            zero_values,
            one_values,
            algorithm,
            used: false,
        }
    }

    /// Returns the public key associated with this private key
    pub fn public_key(&self) -> PublicKey {
        let hash_values = |x: &Vec<Vec<u8>>| -> Vec<Vec<u8>> {
            let buffer_byte = vec![0u8; self.algorithm.output_len];
            let mut buffer = vec![buffer_byte; self.algorithm.output_len * 8];

            for i in 0..self.algorithm.output_len * 8 {
                let mut context = Context::new(self.algorithm);
                context.update(x[i].as_slice());
                buffer[i] = Vec::from(context.finish().as_ref());
            }

            buffer
        };

        let hashed_zero_values = hash_values(&self.zero_values);
        let hashed_one_values = hash_values(&self.one_values);

        PublicKey {
            zero_values: hashed_zero_values,
            one_values: hashed_one_values,
            algorithm: self.algorithm,
        }
    }

    /// Signs the data with the private key and returns the result if successful.
    /// If unsuccesful, an explanation string is returned
    pub fn sign(&mut self, data: &[u8]) -> Result<Vec<Vec<u8>>, &'static str> {
        if self.used {
            return Err("Attempting to sign more than once.");
        }

        let mut context = Context::new(self.algorithm);
        context.update(data);
        let result = context.finish();
        let data_hash = result.as_ref();

        let signature_len = data_hash.len() * 8;
        let mut signature = Vec::with_capacity(signature_len);

        for (i, byte) in data_hash.iter().enumerate() {
            for j in 0..8 {
                let offset = i * 8 + j;
                if (byte & (1 << j)) > 0 {
                    // Bit is 1
                    signature.push(self.one_values[offset].clone());
                } else {
                    // Bit is 0
                    signature.push(self.zero_values[offset].clone());
                }
            }
        }
        self.used = true;
        Ok(signature)
    }
}

impl Drop for PrivateKey {
    fn drop(&mut self) {
        let zeroize_vector = |vector: &mut Vec<Vec<u8>>| {
            for v2 in vector.iter_mut() {
                for byte in v2.iter_mut() {
                    *byte = 0;
                }
            }
        };

        zeroize_vector(&mut self.zero_values);
        zeroize_vector(&mut self.one_values);
    }
}

impl PartialEq for PrivateKey {
    // ⚠ This is not a constant-time implementation
    fn eq(&self, other: &PrivateKey) -> bool {
        if self.algorithm != other.algorithm {
            return false;
        }
        // NOTE: The `zero_values` and `one_values` need not be of the
        // the same length (and maybe this should change).
        let zero_size = self.zero_values.len();
        let one_size = self.one_values.len();
        if zero_size != other.zero_values.len() || one_size != other.one_values.len() {
            return false;
        }

        for i in 0..zero_size {
            if self.zero_values[i] != other.zero_values[i] {
                return false;
            }
        }
        for i in 0..one_size {
            if self.one_values[i] != other.one_values[i] {
                return false;
            }
        }
        true
    }
}

impl Eq for PrivateKey {}

impl PartialOrd for PrivateKey {
    fn partial_cmp(&self, other: &PrivateKey) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for PrivateKey {
    // ⚠ This is not a constant-time implementation
    fn cmp(&self, other: &PrivateKey) -> Ordering {
        self.one_values
            .cmp(&other.one_values)
            .then(self.zero_values.cmp(&other.zero_values))
    }
}

#[cfg(test)]
pub mod tests;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::slice::bytes::copy_memory;

pub static SBOX: [u8, ..256] = [
  0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
  0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
  0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
  0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
  0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
  0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
  0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
  0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
  0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
  0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
  0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
  0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
  0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
  0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
  0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
  0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
];

pub static S2: [u8, ..256] = [
  0xDD, 0x07, 0x8F, 0x5F, 0x7E, 0x12, 0x0E, 0x46, 0xCB, 0xB7, 0xEF, 0x4C, 0xCC, 0xB2, 0xE3, 0x9F,
  0x4A, 0xFD, 0x2F, 0x0F, 0xFF, 0x44, 0x27, 0x2D, 0x2B, 0x61, 0xF7, 0x90, 0x98, 0xDE, 0x20, 0xF6,
  0x87, 0x4F, 0x4D, 0xA3, 0xC8, 0x92, 0xAF, 0x57, 0xB5, 0x00, 0x6B, 0x1A, 0xB0, 0x8D, 0x01, 0x3D,
  0x62, 0xF0, 0x56, 0xFB, 0x9C, 0x58, 0x09, 0xC2, 0x72, 0xDF, 0xA7, 0xDC, 0x23, 0x08, 0x59, 0x47,
  0x9D, 0xBC, 0x29, 0x02, 0xF1, 0x80, 0x99, 0xA1, 0x64, 0x37, 0xCF, 0xEE, 0x1D, 0xBE, 0x31, 0x70,
  0xF2, 0xA5, 0xBF, 0xB1, 0x0A, 0xA0, 0x6D, 0x22, 0xE5, 0x83, 0x54, 0x89, 0xA9, 0x52, 0x69, 0x4E,
  0x91, 0x9A, 0x10, 0xD5, 0x84, 0x8B, 0xE4, 0x28, 0x41, 0x9B, 0xC0, 0x7A, 0xC4, 0xD7, 0xB3, 0x2A,
  0x82, 0x85, 0xEA, 0x16, 0x7D, 0xED, 0x78, 0xE9, 0xD0, 0x42, 0x3F, 0xCA, 0x06, 0x76, 0x9E, 0x51,
  0x50, 0xBD, 0x1E, 0xFE, 0xB6, 0xB4, 0x88, 0x86, 0xD1, 0x4B, 0x2C, 0xD3, 0x17, 0xFA, 0x3B, 0xF4,
  0x55, 0x43, 0x6A, 0x19, 0x48, 0xD2, 0x74, 0x5E, 0x18, 0xF9, 0x53, 0x21, 0x7C, 0x81, 0x35, 0xFC,
  0x38, 0x0B, 0x04, 0xA2, 0x75, 0x65, 0xE8, 0x11, 0x8E, 0x40, 0x6E, 0xC6, 0x6C, 0x93, 0x94, 0xA6,
  0x95, 0xCE, 0x45, 0x63, 0xF3, 0x66, 0x77, 0xE2, 0x71, 0x96, 0xAC, 0x3C, 0x1C, 0xCD, 0x30, 0x5C,
  0x14, 0xC5, 0x49, 0xA8, 0x32, 0xAD, 0x6F, 0x15, 0xC3, 0x03, 0x1F, 0xD9, 0x5A, 0xBA, 0xAB, 0x8A,
  0xE6, 0x67, 0x73, 0xB8, 0x25, 0xDA, 0x33, 0x68, 0x05, 0x1B, 0x34, 0xF8, 0xC1, 0xA4, 0x36, 0xB9,
  0x26, 0xC9, 0x7B, 0xD4, 0xE7, 0x2E, 0x8C, 0x5B, 0xD6, 0xD8, 0xAE, 0xEC, 0x0C, 0xF5, 0x3E, 0xE1,
  0x0D, 0x7F, 0xE0, 0x13, 0xBB, 0x3A, 0x97, 0x5D, 0xEB, 0xAA, 0xC7, 0x39, 0x79, 0x24, 0xDB, 0x60
];

pub fn md2_pad(msg: &[u8]) -> Vec<u8> {
  let mut msg = msg.to_vec();
  let pad = 16 - msg.len() % 16;
  msg.grow_fn(pad, |_| pad as u8);
  msg
}

pub fn md2_checksum(msg: &[u8]) -> [u8, ..16] {
  // Message must be padded.
  assert!(msg.len() % 16 == 0);

  let mut checksum = [0u8, ..16];
  let mut last = 0u8;

  for chunk in msg.chunks(16) {
    for (mbyte, cbyte) in chunk.iter().zip(checksum.iter_mut()) {
      *cbyte ^= SBOX[(*mbyte ^ last) as uint];
      last = *cbyte;
    }
  }

  checksum
}

pub fn md2_compress(state: &[u8], msg: &[u8]) -> [u8, ..16] {
  // Two 128 bit blocks in.
  assert!(state.len() == 16 && msg.len() == 16);

  let mut x = [0u8, ..48];
  let mut result = [0u8, ..16];

  // Copy over the previous state.
  copy_memory(x.slice_mut(0, 16), state);

  // Copy over the message block.
  copy_memory(x.slice_mut(16, 32), msg);

  // XOR the previous state and the message block.
  for (i, byte) in msg.iter().enumerate() {
    x[32 + i] = *byte ^ x[i];
  }

  // Encrypt block (18 rounds).
  let mut t = 0u8;
  for i in range(0, 18) {
    for byte in x.iter_mut() {
      *byte ^= SBOX[t as uint];
      t = *byte;
    }
    t += i;
  }

  // Copy the new state.
  copy_memory(&mut result, x.slice(0, 16));
  result
}

pub fn md2(msg: &[u8]) -> [u8, ..16] {
  // Pad the message to be a multiple of 16 bytes long.
  let msg = md2_pad(msg);

  // Compress all message blocks.
  let state = msg.chunks(16).fold([0u8, ..16], |s, m| md2_compress(&s, m));

  // Compute the checksum.
  let checksum = md2_checksum(msg.as_slice());

  // Compress checksum and return.
  md2_compress(&state, &checksum)
}

#[cfg(test)]
mod test {
  use md2;

  fn hex(buf: &[u8]) -> String {
    buf.iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b))
  }

  fn cmp(d: &str, s: &str) {
    assert_eq!(d.to_string(), hex(&md2(s.as_bytes())));
  }

  #[test]
  fn test_md2() {
    cmp("8350e5a3e24c153df2275c9f80692773", "");
    cmp("32ec01ec4a6dac72c0ab96fb34c0b5d1", "a");
    cmp("da853b0d3f88d99b30283a69e6ded6bb", "abc");
    cmp("ab4f496bfb2a530b219ff33031fe06b0", "message digest");
    cmp("4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz");
    cmp("da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
    cmp("d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
  }
}
<commit_msg>rename inverted s-box<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::slice::bytes::copy_memory;

pub static SBOX: [u8, ..256] = [
  0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
  0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
  0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
  0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
  0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
  0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
  0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
  0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
  0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
  0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
  0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
  0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
  0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
  0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
  0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
  0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
];

pub static SBOXI: [u8, ..256] = [
  0xDD, 0x07, 0x8F, 0x5F, 0x7E, 0x12, 0x0E, 0x46, 0xCB, 0xB7, 0xEF, 0x4C, 0xCC, 0xB2, 0xE3, 0x9F,
  0x4A, 0xFD, 0x2F, 0x0F, 0xFF, 0x44, 0x27, 0x2D, 0x2B, 0x61, 0xF7, 0x90, 0x98, 0xDE, 0x20, 0xF6,
  0x87, 0x4F, 0x4D, 0xA3, 0xC8, 0x92, 0xAF, 0x57, 0xB5, 0x00, 0x6B, 0x1A, 0xB0, 0x8D, 0x01, 0x3D,
  0x62, 0xF0, 0x56, 0xFB, 0x9C, 0x58, 0x09, 0xC2, 0x72, 0xDF, 0xA7, 0xDC, 0x23, 0x08, 0x59, 0x47,
  0x9D, 0xBC, 0x29, 0x02, 0xF1, 0x80, 0x99, 0xA1, 0x64, 0x37, 0xCF, 0xEE, 0x1D, 0xBE, 0x31, 0x70,
  0xF2, 0xA5, 0xBF, 0xB1, 0x0A, 0xA0, 0x6D, 0x22, 0xE5, 0x83, 0x54, 0x89, 0xA9, 0x52, 0x69, 0x4E,
  0x91, 0x9A, 0x10, 0xD5, 0x84, 0x8B, 0xE4, 0x28, 0x41, 0x9B, 0xC0, 0x7A, 0xC4, 0xD7, 0xB3, 0x2A,
  0x82, 0x85, 0xEA, 0x16, 0x7D, 0xED, 0x78, 0xE9, 0xD0, 0x42, 0x3F, 0xCA, 0x06, 0x76, 0x9E, 0x51,
  0x50, 0xBD, 0x1E, 0xFE, 0xB6, 0xB4, 0x88, 0x86, 0xD1, 0x4B, 0x2C, 0xD3, 0x17, 0xFA, 0x3B, 0xF4,
  0x55, 0x43, 0x6A, 0x19, 0x48, 0xD2, 0x74, 0x5E, 0x18, 0xF9, 0x53, 0x21, 0x7C, 0x81, 0x35, 0xFC,
  0x38, 0x0B, 0x04, 0xA2, 0x75, 0x65, 0xE8, 0x11, 0x8E, 0x40, 0x6E, 0xC6, 0x6C, 0x93, 0x94, 0xA6,
  0x95, 0xCE, 0x45, 0x63, 0xF3, 0x66, 0x77, 0xE2, 0x71, 0x96, 0xAC, 0x3C, 0x1C, 0xCD, 0x30, 0x5C,
  0x14, 0xC5, 0x49, 0xA8, 0x32, 0xAD, 0x6F, 0x15, 0xC3, 0x03, 0x1F, 0xD9, 0x5A, 0xBA, 0xAB, 0x8A,
  0xE6, 0x67, 0x73, 0xB8, 0x25, 0xDA, 0x33, 0x68, 0x05, 0x1B, 0x34, 0xF8, 0xC1, 0xA4, 0x36, 0xB9,
  0x26, 0xC9, 0x7B, 0xD4, 0xE7, 0x2E, 0x8C, 0x5B, 0xD6, 0xD8, 0xAE, 0xEC, 0x0C, 0xF5, 0x3E, 0xE1,
  0x0D, 0x7F, 0xE0, 0x13, 0xBB, 0x3A, 0x97, 0x5D, 0xEB, 0xAA, 0xC7, 0x39, 0x79, 0x24, 0xDB, 0x60
];

pub fn md2_pad(msg: &[u8]) -> Vec<u8> {
  let mut msg = msg.to_vec();
  let pad = 16 - msg.len() % 16;
  msg.grow_fn(pad, |_| pad as u8);
  msg
}

pub fn md2_checksum(msg: &[u8]) -> [u8, ..16] {
  // Message must be padded.
  assert!(msg.len() % 16 == 0);

  let mut checksum = [0u8, ..16];
  let mut last = 0u8;

  for chunk in msg.chunks(16) {
    for (mbyte, cbyte) in chunk.iter().zip(checksum.iter_mut()) {
      *cbyte ^= SBOX[(*mbyte ^ last) as uint];
      last = *cbyte;
    }
  }

  checksum
}

pub fn md2_compress(state: &[u8], msg: &[u8]) -> [u8, ..16] {
  // Two 128 bit blocks in.
  assert!(state.len() == 16 && msg.len() == 16);

  let mut x = [0u8, ..48];
  let mut result = [0u8, ..16];

  // Copy over the previous state.
  copy_memory(x.slice_mut(0, 16), state);

  // Copy over the message block.
  copy_memory(x.slice_mut(16, 32), msg);

  // XOR the previous state and the message block.
  for (i, byte) in msg.iter().enumerate() {
    x[32 + i] = *byte ^ x[i];
  }

  // Encrypt block (18 rounds).
  let mut t = 0u8;
  for i in range(0, 18) {
    for byte in x.iter_mut() {
      *byte ^= SBOX[t as uint];
      t = *byte;
    }
    t += i;
  }

  // Copy the new state.
  copy_memory(&mut result, x.slice(0, 16));
  result
}

pub fn md2(msg: &[u8]) -> [u8, ..16] {
  // Pad the message to be a multiple of 16 bytes long.
  let msg = md2_pad(msg);

  // Compress all message blocks.
  let state = msg.chunks(16).fold([0u8, ..16], |s, m| md2_compress(&s, m));

  // Compute the checksum.
  let checksum = md2_checksum(msg.as_slice());

  // Compress checksum and return.
  md2_compress(&state, &checksum)
}

#[cfg(test)]
mod test {
  use md2;

  fn hex(buf: &[u8]) -> String {
    buf.iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b))
  }

  fn cmp(d: &str, s: &str) {
    assert_eq!(d.to_string(), hex(&md2(s.as_bytes())));
  }

  #[test]
  fn test_md2() {
    cmp("8350e5a3e24c153df2275c9f80692773", "");
    cmp("32ec01ec4a6dac72c0ab96fb34c0b5d1", "a");
    cmp("da853b0d3f88d99b30283a69e6ded6bb", "abc");
    cmp("ab4f496bfb2a530b219ff33031fe06b0", "message digest");
    cmp("4e8ddff3650292ab5a4108c3aa47940b", "abcdefghijklmnopqrstuvwxyz");
    cmp("da33def2a42df13975352846c30338cd", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
    cmp("d5976f79d83d3a0dc9806c3c66f3efd8", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
  }
}
<|endoftext|>


<commit_before>mod connection;
mod error;
mod runner;
mod server;
mod target;

pub use connection::DBusConnection as DBusConnection;
pub use error::DBusError as DBusError;
pub use runner::DBusRunner as DBusRunner;
pub use server::DBusServer as DBusServer;
pub use target::DBusTarget as DBusTarget;
<commit_msg>lib: simplify re-exports<commit_after>mod connection;
mod error;
mod runner;
mod server;
mod target;

pub use connection::DBusConnection;
pub use error::DBusError;
pub use runner::DBusRunner;
pub use server::DBusServer;
pub use target::DBusTarget;
<|endoftext|>


<commit_before>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

static START_ADDR: u16 = 0x200;
static MEM_SIZE: uint = 4096;
pub static DISPLAY_WIDTH: uint = 64;
pub static DISPLAY_HEIGHT: uint = 32;

static FONTSET: [u8, .. 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut ch8 = VirtualMachine::new(dump_pixels);
///     // ...
/// ```
pub type DrawCallback<'a> = |pixels: &[u8]|: 'a;

struct KeypressWait {
    wait: bool,
    vx: uint
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>,
    keys: [bool, .. 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0, .. MEM_SIZE],
            v: [0, .. 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0, .. 16],
            display: [0, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false, .. 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(ch8.ram.slice_mut(0u, 5 * 0x10), FONTSET);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.slice_mut(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as uint),
            0x3 => ops::skip_next_vx_eq(self, x as uint, kk),
            0x4 => ops::skip_next_vx_ne(self, x as uint, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as uint, kk),
            0x7 => ops::add_vx_byte(self, x as uint, kk),
            0x8 => {
                let (x, y) = (x as uint, y as uint);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => fail!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as uint, kk),
            0xD => ops::display_sprite(self, x as uint, y as uint, n as uint),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as uint),
                0x9E => ops::skip_next_key_vx_pressed(self, x as uint),
                _ => fail!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as uint),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as uint),
                    0x15 => ops::set_delay_timer(self, x as uint),
                    0x18 => ops::set_sound_timer(self, x as uint),
                    0x1E => ops::add_vx_to_i(self, x as uint),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as uint),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as uint),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as uint),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as uint),
                    _ => fail!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => fail!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        self.pc += 2;
        b1 as u16 << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<commit_msg>Use `const` for constants<commit_after>//! CHIP-8 emulator backend.
//! You can develop your own frontends for it.
//!
//! The reference frontend is
//! [crusty-chip-sfml](https://github.com/crumblingstatue/crusty-chip-sfml).
//!
//! The CHIP-8 technical documentation in the comments is copied from
//! http://devernay.free.fr/hacks/chip8/C8TECH10.HTM,
//! Copyright (c) Thomas P. Greene.

#![experimental]

use std::slice::bytes::copy_memory;

mod ops;

const START_ADDR: u16 = 0x200;
const MEM_SIZE: uint = 4096;
pub const DISPLAY_WIDTH: uint = 64;
pub const DISPLAY_HEIGHT: uint = 32;

static FONTSET: [u8, .. 5 * 0x10] = [
    0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
    0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
    0x90, 0x90, 0xF0, 0x10, 0x10, // 4
    0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
    0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
    0xF0, 0x10, 0x20, 0x40, 0x40, // 7
    0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
    0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
    0xF0, 0x90, 0xF0, 0x90, 0x90, // A
    0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
    0xF0, 0x80, 0x80, 0x80, 0xF0, // C
    0xE0, 0x90, 0x90, 0x90, 0xE0, // D
    0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
    0xF0, 0x80, 0xF0, 0x80, 0x80, // F
];

/// Draw callback.
///
/// Takes a slice of u8, where each u8 is a pixel.
///
/// A **non-zero** pixel is visible, a **zero** pixel is not visible.
///
/// The coordinate system is from top-left to bottom-right.
///
/// Example:
///
/// ```rust
///     use crusty_chip::{ DISPLAY_WIDTH, VirtualMachine };
///     // Dump the pixels to stdout
///     fn dump_pixels(pixels: &[u8]) {
///         for (i, px) in pixels.iter().enumerate() {
///             match *px {
///                 0 => print!(" "),
///                 _ => print!("#")
///             }
///             if i % DISPLAY_WIDTH == 0 {
///                 print!("\n");
///             }
///         }
///     }
///     let mut ch8 = VirtualMachine::new(dump_pixels);
///     // ...
/// ```
pub type DrawCallback<'a> = |pixels: &[u8]|: 'a;

struct KeypressWait {
    wait: bool,
    vx: uint
}

/// CHIP-8 virtual machine
pub struct VirtualMachine<'a> {
    ram: [u8, .. MEM_SIZE],
    v: [u8, .. 16],
    i: u16,
    delay_timer: u8,
    sound_timer: u8,
    pc: u16,
    sp: u8,
    stack: [u16, .. 16],
    display: [u8, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
    draw_callback: DrawCallback<'a>,
    keys: [bool, .. 16],
    keypress_wait: KeypressWait
}

impl <'a> VirtualMachine <'a> {

    /// Constructs a new `VirtualMachine`.
    ///
    /// ## Arguments ##
    /// * draw_callback - Callback used when drawing
    pub fn new(draw_callback: DrawCallback<'a>) -> VirtualMachine<'a> {
        let mut ch8 = VirtualMachine {
            ram: [0, .. MEM_SIZE],
            v: [0, .. 16],
            i: 0,
            delay_timer: 0,
            sound_timer: 0,
            pc: START_ADDR,
            sp: 0,
            stack: [0, .. 16],
            display: [0, .. DISPLAY_WIDTH * DISPLAY_HEIGHT],
            draw_callback: draw_callback,
            keys: [false, .. 16],
            keypress_wait: KeypressWait {
                wait: false,
                vx: 0
            }
        };
        copy_memory(ch8.ram.slice_mut(0u, 5 * 0x10), FONTSET);
        ch8
    }

    /// Load a ROM
    ///
    /// ## Arguments ##
    /// * rom - ROM to load
    pub fn load_rom(&mut self, rom: &[u8]) {
        let len = self.ram.len();
        copy_memory(self.ram.slice_mut(START_ADDR as uint, len), rom);
    }

    /// Do an emulation cycle.
    pub fn do_cycle(&mut self) {
        if self.keypress_wait.wait {
            return;
        }

        let ins = self.fetch_ins();
        self.dispatch(ins);
    }

    // Decode instruction and execute it
    fn dispatch(&mut self, ins: u16) {
        // A 12-bit value, the lowest 12 bits of the instruction
        let nnn = ins & 0x0FFF;
        // A 4-bit value, the lowest 4 bits of the instruction
        let n = ins & 0x000F;
        // A 4-bit value, the lower 4 bits of the high byte of the instruction
        let x = (ins & 0x0F00) >> 8;
        // A 4-bit value, the upper 4 bits of the low byte of the instruction
        let y = (ins & 0x00F0) >> 4;
        // kk or byte - An 8-bit value, the lowest 8 bits of the instruction
        let kk = (ins & 0x00FF) as u8;

        match (ins & 0xF000) >> 12 {
            0x0 => match nnn {
                0x0E0 => ops::clear_display(self, ),
                0x0EE => ops::ret_from_subroutine(self, ),
                _ => ops::jump_to_sys_routine(self, 0)
            },
            0x1 => ops::jump_addr(self, nnn),
            0x2 => ops::call_subroutine(self, nnn as uint),
            0x3 => ops::skip_next_vx_eq(self, x as uint, kk),
            0x4 => ops::skip_next_vx_ne(self, x as uint, kk),
            0x5 => match n {
                0x0 => ops::skip_next_vx_eq_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x5XXX instruction: {:x}", ins)
            },
            0x6 => ops::set_vx_byte(self, x as uint, kk),
            0x7 => ops::add_vx_byte(self, x as uint, kk),
            0x8 => {
                let (x, y) = (x as uint, y as uint);
                match n {
                    0x0 => ops::set_vx_to_vy(self, x, y),
                    0x1 => ops::set_vx_to_vx_or_vy(self, x, y),
                    0x2 => ops::set_vx_to_vx_and_vy(self, x, y),
                    0x3 => ops::set_vx_to_vx_xor_vy(self, x, y),
                    0x4 => ops::add_vx_vy(self, x, y),
                    0x5 => ops::sub_vx_vy(self, x, y),
                    0x6 => ops::set_vx_to_vx_shr_1(self, x),
                    0xE => ops::set_vx_to_vx_shl_1(self, x),
                    _ => fail!("Unknown 0x8XXX instruction: {:x}", ins)
                }
            },
            0x9 => match n {
                0x0 => ops::skip_next_vx_ne_vy(self, x as uint, y as uint),
                _ => fail!("Unknown 0x9XXX instruction: {:x}", ins)
            },
            0xA => ops::set_i(self, nnn),
            0xC => ops::set_vx_rand_and(self, x as uint, kk),
            0xD => ops::display_sprite(self, x as uint, y as uint, n as uint),
            0xE => match kk {
                0xA1 => ops::skip_next_key_vx_not_pressed(self, x as uint),
                0x9E => ops::skip_next_key_vx_pressed(self, x as uint),
                _ => fail!("Unknown 0xEXXX instruction: {:x}", ins)
            },
            0xF => {
                match kk {
                    0x07 => ops::set_vx_to_delay_timer(self, x as uint),
                    0x0A => ops::wait_for_keypress_store_in_vx(self, x as uint),
                    0x15 => ops::set_delay_timer(self, x as uint),
                    0x18 => ops::set_sound_timer(self, x as uint),
                    0x1E => ops::add_vx_to_i(self, x as uint),
                    0x29 => ops::set_i_to_loc_of_digit_vx(self, x as uint),
                    0x33 => ops::store_bcd_of_vx_to_i(self, x as uint),
                    0x55 => ops::copy_v0_through_vx_to_mem(self, x as uint),
                    0x65 => ops::read_v0_through_vx_from_mem(self, x as uint),
                    _ => fail!("Unknown 0xFXXX instruction: {:x}", ins)
                }
            },
            _ => fail!("Unknown instruction: {:04x}", ins)
        }
    }

    fn fetch_ins(&mut self) -> u16 {
        let b1 = self.ram[self.pc as uint];
        let b2 = self.ram[(self.pc + 1) as uint];
        self.pc += 2;
        b1 as u16 << 8 | b2 as u16
    }

    /// Press a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn press_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = true;
        if self.keypress_wait.wait {
            self.v[self.keypress_wait.vx] = key as u8;
            self.keypress_wait.wait = false;
        }
    }

    /// Release a key on the hexadecimal keypad
    ///
    /// `key` should be in the range `0..15`
    pub fn release_key(&mut self, key: uint) {
        assert!(key <= 15);
        self.keys[key] = false;
    }

    /// Decrement the sound and delay timers
    ///
    /// They should be decremented at a rate of 60 Hz
    pub fn decrement_timers(&mut self) {
        if self.delay_timer > 0 {
            self.delay_timer -= 1;
        }
        if self.sound_timer > 0 {
            self.sound_timer -= 1;
        }
    }
}
<|endoftext|>


<commit_before>extern crate getopts;

use getopts::{Options, ParsingStyle};
use std::io::{stdout, Write};
use std::fmt;
use std::iter::repeat;

/// Version of this crate. It is parsed from the environment variable that
/// cargo sets when building the crate.
pub const VERSION: &'static str         = env!("CARGO_PKG_VERSION");

/// Name of this tool.
pub const NAME: &'static str            = "yes";

/// A description of this tool.
pub const DESCRIPTION: &'static str     = "Repeats a given string and a newline \
character infinitely on stdout.";

/// The default string to repeat.
pub const DEFAULT_STRING: &'static str  = "y";

/// The buffer size to use when printing the repeated string.
pub const BUFSIZE: usize                = 16384;

/// Represents a request, this tells the `yes` utility what it has to do.
/// Depending on the options passed on the command line, we might take
/// different actions, which are represented here.
#[derive(Debug, PartialEq)]
pub enum Request {
    /// Main purpose of this utility: send a given string followed by a newline
    /// repeatedly to `stdout`.
    RepeatString(String),

    /// Print help information to `stdout`.
    ShowHelp,

    /// Print the utility’s version number to `stdout`.
    ShowVersion
}

/// These are all the errors that can occur in this utility.
#[derive(Debug, PartialEq)]
pub enum Error {

    /// An invalid option was encountered while parsing the options.
    InvalidOption(getopts::Fail)
}

use Request::*;
use Error::*;

impl Error {
    /// Returns the error message associated with the error.
    pub fn message(&self) -> String {
        match *self {
            InvalidOption(ref fail) => fail.to_string()
        }
    }

    /// Prints the error to stderr.
    pub fn show(&self) {
        eprintln!("{}", self.message());
    }
}

impl fmt::Display for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ShowHelp            => write!(f, "{}", help_text()),
            ShowVersion         => write!(f, "{}", version_text()),
            RepeatString(ref s) => write!(f, "{}", s)
        }
    }
}

impl Request {
    /// Do the request. This performs the action suggested by the request.
    pub fn do_it(&self) {
        match *self {
            ShowHelp => println!("{}", self),
            ShowVersion => println!("{}", self),
            RepeatString(ref s) => repeat_string(s)
        }
    }
}

/// Create an options object.
fn options() -> Options {
    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::StopAtFirstFree);

    // command-line options that this utility supports
    opts.optflag("h", "help", "display help text and exit");
    opts.optflag("v", "version", "output version information and exit");

    opts
}

/// Parse the command line arguments as options, returning either the parsed
/// `Request` or an `Error`, depending on the arguments.
pub fn parse_args(args: Vec<String>) -> Result<Request, Error> {
    // parse the command-line arguments, and return on error.
    let matches = match options().parse(args) {
        Ok(matches)  => matches,
        Err(failure) => return Err(InvalidOption(failure))
    };

    // if the help flag is set, we want to show the help text.
    if matches.opt_present("help") {
        return Ok(ShowHelp);
    }

    // if the version flag is set, we want to show the version.
    if matches.opt_present("version") {
        return Ok(ShowVersion);
    }

    // if there is no string set, we use the default one, otherwise we take the
    // free strings and join them together.
    let string = if matches.free.is_empty() {
        DEFAULT_STRING.to_owned()
    } else {
        matches.free.join(" ")
    };

    Ok(RepeatString(string))
}

#[test]
fn test_parse_args() {
    // test help options
    assert_eq!(parse_args(vec!["-h".to_string()]), Ok(ShowHelp));
    assert_eq!(parse_args(vec!["--help".to_string()]), Ok(ShowHelp));

    // test version options
    assert_eq!(parse_args(vec!["-v".to_string()]), Ok(ShowVersion));
    assert_eq!(parse_args(vec!["--version".to_string()]), Ok(ShowVersion));

    // use the DEAFULT_STRING if nothing is specified
    assert_eq!(parse_args(vec![]), Ok(RepeatString(DEFAULT_STRING.to_string())));

    // use whatever is given on command line
    assert_eq!(parse_args(vec!["str".to_string()]),
               Ok(RepeatString("str".to_string())));

    // join multiple arguments together
    assert_eq!(parse_args(vec!["str".to_string(), "dup".to_string()]),
               Ok(RepeatString("str dup".to_string())));

    // allow command line flags as string
    assert_eq!(parse_args(vec!["--".to_string(), "-h".to_string()]),
               Ok(RepeatString("-h".to_string())));
}

/// Generates a help text using the `getopts` crate. It is derived from the
/// `NAME`, the `DESCRIPTION`, as well as from the options.
pub fn help_text() -> String {
    let opts = options();
    let short_usage = format!("{} [STRING]", opts.short_usage(NAME));
    opts.usage(&short_usage)
}

/// Generates a version text, uses the `VERSION` as well as the `NAME` consts.
pub fn version_text() -> String {
    format!("{} version {}", NAME, VERSION)
}

/// Print a string repeatedly to `stdout`.
pub fn repeat_string(string: &str) {
    // creates a buffer, containing a lot of repetitions of our string
    let buf = repeat_buffer(string);

    // create a handle to stdout
    let stdout = stdout();
    let mut stdout = stdout.lock();

    // continuously print to stdout
    loop {
        match stdout.write_all(buf.as_bytes()) {
            Ok(_) => continue,
            Err(_) => break
        }
    }
}

/// Generates a buffer, which is maximally `BUFSIZE` big, consisting of the
/// string repeated as many times as will fit into the buffer, joined with
/// newline characters.
pub fn repeat_buffer(string: &str) -> String {
    // append newline to string
    let mut s = string.to_owned();
    s.push('\n');

    // calculate how many times our string fits into a bufsize
    let times = BUFSIZE / s.len();

    // repeat the string this many times and join it together
    repeat(s).take(times).collect::<Vec<String>>().join("")
}
<commit_msg>expands test of parse_args()<commit_after>extern crate getopts;

use getopts::{Options, ParsingStyle};
use std::io::{stdout, Write};
use std::fmt;
use std::iter::repeat;

/// Version of this crate. It is parsed from the environment variable that
/// cargo sets when building the crate.
pub const VERSION: &'static str         = env!("CARGO_PKG_VERSION");

/// Name of this tool.
pub const NAME: &'static str            = "yes";

/// A description of this tool.
pub const DESCRIPTION: &'static str     = "Repeats a given string and a newline \
character infinitely on stdout.";

/// The default string to repeat.
pub const DEFAULT_STRING: &'static str  = "y";

/// The buffer size to use when printing the repeated string.
pub const BUFSIZE: usize                = 16384;

/// Represents a request, this tells the `yes` utility what it has to do.
/// Depending on the options passed on the command line, we might take
/// different actions, which are represented here.
#[derive(Debug, PartialEq)]
pub enum Request {
    /// Main purpose of this utility: send a given string followed by a newline
    /// repeatedly to `stdout`.
    RepeatString(String),

    /// Print help information to `stdout`.
    ShowHelp,

    /// Print the utility’s version number to `stdout`.
    ShowVersion
}

/// These are all the errors that can occur in this utility.
#[derive(Debug, PartialEq)]
pub enum Error {
    /// An invalid option was encountered while parsing the options.
    InvalidOption(getopts::Fail)
}

use Request::*;
use Error::*;

impl Error {
    /// Returns the error message associated with the error.
    pub fn message(&self) -> String {
        match *self {
            InvalidOption(ref fail) => fail.to_string()
        }
    }

    /// Prints the error to stderr.
    pub fn show(&self) {
        eprintln!("{}", self.message());
    }
}

impl fmt::Display for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ShowHelp            => write!(f, "{}", help_text()),
            ShowVersion         => write!(f, "{}", version_text()),
            RepeatString(ref s) => write!(f, "{}", s)
        }
    }
}

impl Request {
    /// Do the request. This performs the action suggested by the request.
    pub fn do_it(&self) {
        match *self {
            ShowHelp => println!("{}", self),
            ShowVersion => println!("{}", self),
            RepeatString(ref s) => repeat_string(s)
        }
    }
}

/// Create an options object.
fn options() -> Options {
    let mut opts = Options::new();
    opts.parsing_style(ParsingStyle::StopAtFirstFree);

    // command-line options that this utility supports
    opts.optflag("h", "help", "display help text and exit");
    opts.optflag("v", "version", "output version information and exit");

    opts
}

/// Parse the command line arguments as options, returning either the parsed
/// `Request` or an `Error`, depending on the arguments.
pub fn parse_args(args: Vec<String>) -> Result<Request, Error> {
    // parse the command-line arguments, and return on error.
    let matches = match options().parse(args) {
        Ok(matches)  => matches,
        Err(failure) => return Err(InvalidOption(failure))
    };

    // if the help flag is set, we want to show the help text.
    if matches.opt_present("help") {
        return Ok(ShowHelp);
    }

    // if the version flag is set, we want to show the version.
    if matches.opt_present("version") {
        return Ok(ShowVersion);
    }

    // if there is no string set, we use the default one, otherwise we take the
    // free strings and join them together.
    let string = if matches.free.is_empty() {
        DEFAULT_STRING.to_owned()
    } else {
        matches.free.join(" ")
    };

    Ok(RepeatString(string))
}

#[test]
fn test_parse_args() {
    // test help options
    assert_eq!(parse_args(vec!["-h".to_string()]), Ok(ShowHelp));
    assert_eq!(parse_args(vec!["--help".to_string()]), Ok(ShowHelp));

    // test version options
    assert_eq!(parse_args(vec!["-v".to_string()]), Ok(ShowVersion));
    assert_eq!(parse_args(vec!["--version".to_string()]), Ok(ShowVersion));

    // use the DEAFULT_STRING if nothing is specified
    assert_eq!(parse_args(vec![]), Ok(RepeatString(DEFAULT_STRING.to_string())));

    // use whatever is given on command line
    assert_eq!(parse_args(vec!["str".to_string()]),
               Ok(RepeatString("str".to_string())));

    // join multiple arguments together
    assert_eq!(parse_args(vec!["str".to_string(), "dup".to_string()]),
               Ok(RepeatString("str dup".to_string())));

    // allow command line flags as string
    assert_eq!(parse_args(vec!["--".to_string(), "-h".to_string()]),
               Ok(RepeatString("-h".to_string())));

    // check if it returns an error when encountering illegal arguments
    assert!(parse_args(vec!["-g".to_string()]).is_err());
    match parse_args(vec!["--global".to_string()]) {
        Err(InvalidOption(_)) => assert!(true),
        _ => assert!(false)
    }

}

/// Generates a help text using the `getopts` crate. It is derived from the
/// `NAME`, the `DESCRIPTION`, as well as from the options.
pub fn help_text() -> String {
    let opts = options();
    let short_usage = format!("{} [STRING]", opts.short_usage(NAME));
    opts.usage(&short_usage)
}

/// Generates a version text, uses the `VERSION` as well as the `NAME` consts.
pub fn version_text() -> String {
    format!("{} version {}", NAME, VERSION)
}

/// Print a string repeatedly to `stdout`.
pub fn repeat_string(string: &str) {
    // creates a buffer, containing a lot of repetitions of our string
    let buf = repeat_buffer(string);

    // create a handle to stdout
    let stdout = stdout();
    let mut stdout = stdout.lock();

    // continuously print to stdout
    loop {
        match stdout.write_all(buf.as_bytes()) {
            Ok(_) => continue,
            Err(_) => break
        }
    }
}

/// Generates a buffer, which is maximally `BUFSIZE` big, consisting of the
/// string repeated as many times as will fit into the buffer, joined with
/// newline characters.
pub fn repeat_buffer(string: &str) -> String {
    // append newline to string
    let mut s = string.to_owned();
    s.push('\n');

    // calculate how many times our string fits into a bufsize
    let times = BUFSIZE / s.len();

    // repeat the string this many times and join it together
    repeat(s).take(times).collect::<Vec<String>>().join("")
}
<|endoftext|>


<commit_before>#![feature(core, rustc_private, collections)]
#![feature(plugin_registrar, quote, slicing_syntax)]
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use syntax::ast::{self, TokenTree};
use syntax::codemap::DUMMY_SP;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacItems, MacResult};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::tts_to_parser;

use generator::Generate;

mod block;
mod parser;
mod generator;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("speculate", expand_speculate);
}

fn expand_speculate(cx: &mut ExtCtxt, _sp: Span, tokens: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = tts_to_parser(cx.parse_sess(), tokens.to_vec(), cx.cfg());
    let block = parser::parse(&mut parser);
    let item = block.generate(cx, None);

    let attrs = vec![
        cx.attribute(
            DUMMY_SP,
            cx.meta_list(
                DUMMY_SP,
                token::InternedString::new("allow"),
                vec![
                    cx.meta_word(
                        DUMMY_SP,
                        token::InternedString::new("non_snake_case"))
                ]
            )
        )
    ];

    let pub_use_super_star = cx.item_use_glob(DUMMY_SP,
                                              ast::Visibility::Public,
                                              vec![cx.ident_of("super")]);

    let module = cx.item_mod(DUMMY_SP, DUMMY_SP, cx.ident_of("sup"),
                             attrs, vec![pub_use_super_star, item]);

    MacItems::new(Some(module).into_iter())
}
<commit_msg>Fix for `rustc 1.0.0-dev (a2aee6290 2015-02-01 04:21:09 +0000)`.<commit_after>#![feature(rustc_private)]
#![feature(plugin_registrar, quote, slicing_syntax)]
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use syntax::ast::{self, TokenTree};
use syntax::codemap::DUMMY_SP;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacItems, MacResult};
use syntax::ext::build::AstBuilder;
use syntax::parse::token;
use syntax::parse::tts_to_parser;

use generator::Generate;

mod block;
mod parser;
mod generator;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("speculate", expand_speculate);
}

fn expand_speculate(cx: &mut ExtCtxt, _sp: Span, tokens: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = tts_to_parser(cx.parse_sess(), tokens.to_vec(), cx.cfg());
    let block = parser::parse(&mut parser);
    let item = block.generate(cx, None);

    let attrs = vec![
        cx.attribute(
            DUMMY_SP,
            cx.meta_list(
                DUMMY_SP,
                token::InternedString::new("allow"),
                vec![
                    cx.meta_word(
                        DUMMY_SP,
                        token::InternedString::new("non_snake_case"))
                ]
            )
        )
    ];

    let pub_use_super_star = cx.item_use_glob(DUMMY_SP,
                                              ast::Visibility::Public,
                                              vec![cx.ident_of("super")]);

    let module = cx.item_mod(DUMMY_SP, DUMMY_SP, cx.ident_of("sup"),
                             attrs, vec![pub_use_super_star, item]);

    MacItems::new(Some(module).into_iter())
}
<|endoftext|>


<commit_before>//! # Feature flags
//!
//! This crate exposes a number of features. These can be enabled or disabled as shown
//! [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html). Features
//! are _disabled_ by default unless otherwise noted.
//!
//! Reliance on a given feature is always indicated alongside the item definition.
//!
//! - `std` (_enabled by default, implicitly enables `alloc`_)
//!
//!   This enables a number of features that depend on the standard library.
//!
//! - `alloc` (_enabled by default via `std`_)
//!
//!   Enables a number of features that require the ability to dynamically allocate memory.
//!
//! - `macros`
//!
//!   Enables macros that provide compile-time verification of values and intuitive syntax.
//!
//! - `formatting` (_implicitly enables `std`_)
//!
//!   Enables formatting of most structs.
//!
//! - `parsing`
//!
//!   Enables parsing of most structs.
//!
//! - `local-offset` (_implicitly enables `std`_)
//!
//!   This feature enables a number of methods that allow obtaining the system's UTC offset.
//!
//! - `large-dates`
//!
//!   By default, only years within the ±9999 range (inclusive) are supported. If you need support
//!   for years outside this range, consider enabling this feature; the supported range will be
//!   increased to ±999,999.
//!
//!   Note that enabling this feature has some costs, as it means forgoing some optimizations.
//!   Ambiguities may be introduced when parsing that would not otherwise exist.
//!
//!   If you are using this feature, **please leave a comment**
//!   [on this discussion](https://github.com/time-rs/time/discussions/306) with your use case. If
//!   there is not sufficient demand for this feature, it will be dropped in a future release.
//!
//! - `serde`
//!
//!   Enables [serde](https://docs.rs/serde) support for all types.
//!
//! - `serde-human-readable` (_implicitly enables `serde`, `formatting`, and `parsing`_)
//!
//!   Allows serde representations to use a human-readable format. This is determined by the
//!   serializer, not the user. If this feature is not enabled or if the serializer requests a
//!   non-human-readable format, a format optimized for binary representation will be used.
//!
//!   Libraries should never enable this feature, as the decision of what format to use should be up
//!   to the user.
//!
//! - `serde-well-known` (_implicitly enables `serde/alloc`, `formatting`, and `parsing`_)
//!
//!   Enables support for serializing and deserializing well-known formats using serde's
//!   [`#[with]` attribute](https://serde.rs/field-attrs.html#with).
//!
//! - `rand`
//!
//!   Enables [rand](https://docs.rs/rand) support for all types.
//!
//! - `quickcheck` (_implicitly enables `alloc`_)
//!
//!   Enables [quickcheck](https://docs.rs/quickcheck) support for all types except [`Instant`].
//!
//! One pseudo-feature flag that is only available to end users is the `unsound_local_offset` cfg.
//! As the name indicates, using the feature is unsound, and [may cause unexpected segmentation
//! faults](https://github.com/time-rs/time/issues/293). Unlike other flags, this is deliberately
//! only available to end users; this is to ensure that a user doesn't have unsound behavior without
//! knowing it. To enable this behavior, you must use `RUSTFLAGS="--cfg unsound_local_offset" cargo
//! build` or similar. Note: This flag is _not tested anywhere_, including in the regular test of
//! the powerset of all feature flags. Use at your own risk. Without this flag, any method that
//! requires the local offset will return the `Err` variant.

#![doc(html_playground_url = "https://play.rust-lang.org")]
#![cfg_attr(__time_03_docs, feature(doc_cfg, doc_auto_cfg, doc_notable_trait))]
#![cfg_attr(
    __time_03_docs,
    deny(rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links)
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
    anonymous_parameters,
    clippy::all,
    const_err,
    illegal_floating_point_literal_pattern,
    late_bound_lifetime_arguments,
    path_statements,
    patterns_in_fns_without_body,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unsafe_code,
    unsafe_op_in_unsafe_fn,
    unused_extern_crates
)]
#![warn(
    clippy::dbg_macro,
    clippy::decimal_literal_representation,
    clippy::get_unwrap,
    clippy::missing_docs_in_private_items,
    clippy::nursery,
    clippy::print_stdout,
    clippy::todo,
    clippy::unimplemented,
    clippy::unnested_or_patterns,
    clippy::unwrap_in_result,
    clippy::unwrap_used,
    clippy::use_debug,
    deprecated_in_future,
    missing_copy_implementations,
    missing_debug_implementations,
    unused_qualifications,
    variant_size_differences
)]
#![allow(clippy::redundant_pub_crate)]
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(test(attr(deny(warnings))))]

#[allow(unused_extern_crates)]
#[cfg(feature = "alloc")]
extern crate alloc;

// region: macros
/// Helper macro for easily implementing `OpAssign`.
macro_rules! __impl_assign {
    ($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$(
        #[allow(unused_qualifications)]
        $(#[$attr])*
        impl core::ops::$op<$t> for $target {
            fn $fn(&mut self, rhs: $t) {
                *self = *self $sym rhs;
            }
        }
    )+};
}

/// Implement `AddAssign` for the provided types.
macro_rules! impl_add_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(+ AddAssign add_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `SubAssign` for the provided types.
macro_rules! impl_sub_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(- SubAssign sub_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `MulAssign` for the provided types.
macro_rules! impl_mul_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(* MulAssign mul_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `DivAssign` for the provided types.
macro_rules! impl_div_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(/ DivAssign div_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Division of integers, rounding the resulting value towards negative infinity.
macro_rules! div_floor {
    ($a:expr, $b:expr) => {{
        let _a = $a;
        let _b = $b;

        let (_quotient, _remainder) = (_a / _b, _a % _b);

        if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
            _quotient - 1
        } else {
            _quotient
        }
    }};
}

/// Cascade an out-of-bounds value.
macro_rules! cascade {
    (@ordinal ordinal) => {};
    (@year year) => {};

    // Cascade an out-of-bounds value from "from" to "to".
    ($from:ident in $min:literal.. $max:literal => $to:tt) => {
        #[allow(unused_comparisons, unused_assignments)]
        if $from >= $max {
            $from -= $max - $min;
            $to += 1;
        } else if $from < $min {
            $from += $max - $min;
            $to -= 1;
        }
    };

    // Special case the ordinal-to-year cascade, as it has different behavior.
    ($ordinal:ident => $year:ident) => {
        // We need to actually capture the idents. Without this, macro hygiene causes errors.
        cascade!(@ordinal $ordinal);
        cascade!(@year $year);
        #[allow(unused_assignments)]
        if $ordinal > crate::util::days_in_year($year) {
            $year += 1;
            $ordinal = 1;
        } else if $ordinal == 0 {
            $year -= 1;
            $ordinal = crate::util::days_in_year($year);
        }
    };
}

/// Returns `Err(error::ComponentRange)` if the value is not in range.
macro_rules! ensure_value_in_range {
    ($value:ident in $start:expr => $end:expr) => {{
        let _start = $start;
        let _end = $end;
        #[allow(trivial_numeric_casts, unused_comparisons)]
        if $value < _start || $value > _end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: _start as _,
                maximum: _end as _,
                value: $value as _,
                conditional_range: false,
            });
        }
    }};

    ($value:ident conditionally in $start:expr => $end:expr) => {{
        let _start = $start;
        let _end = $end;
        #[allow(trivial_numeric_casts, unused_comparisons)]
        if $value < _start || $value > _end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: _start as _,
                maximum: _end as _,
                value: $value as _,
                conditional_range: true,
            });
        }
    }};
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is
/// usable in `const` contexts.
macro_rules! const_try {
    ($e:expr) => {
        match $e {
            Ok(value) => value,
            Err(error) => return Err(error),
        }
    };
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but is usable in `const` contexts.
macro_rules! const_try_opt {
    ($e:expr) => {
        match $e {
            Some(value) => value,
            None => return None,
        }
    };
}
// endregion macros

mod date;
mod duration;
pub mod error;
pub mod ext;
#[cfg(any(feature = "formatting", feature = "parsing"))]
pub mod format_description;
#[cfg(feature = "formatting")]
pub mod formatting;
#[cfg(feature = "std")]
mod instant;
#[cfg(feature = "macros")]
pub mod macros;
mod month;
mod offset_date_time;
#[cfg(feature = "parsing")]
pub mod parsing;
mod primitive_date_time;
#[cfg(feature = "quickcheck")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "quickcheck")))]
mod quickcheck;
#[cfg(feature = "rand")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "rand")))]
mod rand;
#[cfg(feature = "serde")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "serde")))]
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub mod serde;
mod sys;
#[cfg(test)]
mod tests;
mod time;
mod utc_offset;
pub mod util;
mod weekday;

pub use crate::date::Date;
pub use crate::duration::Duration;
pub use crate::error::Error;
#[cfg(feature = "std")]
pub use crate::instant::Instant;
pub use crate::month::Month;
pub use crate::offset_date_time::OffsetDateTime;
pub use crate::primitive_date_time::PrimitiveDateTime;
pub use crate::time::Time;
pub use crate::utc_offset::UtcOffset;
pub use crate::weekday::Weekday;

/// An alias for [`std::result::Result`] with a generic error from the time crate.
pub type Result<T> = core::result::Result<T, Error>;
<commit_msg>Mention, that Instant has no serde support<commit_after>//! # Feature flags
//!
//! This crate exposes a number of features. These can be enabled or disabled as shown
//! [in Cargo's documentation](https://doc.rust-lang.org/cargo/reference/features.html). Features
//! are _disabled_ by default unless otherwise noted.
//!
//! Reliance on a given feature is always indicated alongside the item definition.
//!
//! - `std` (_enabled by default, implicitly enables `alloc`_)
//!
//!   This enables a number of features that depend on the standard library.
//!
//! - `alloc` (_enabled by default via `std`_)
//!
//!   Enables a number of features that require the ability to dynamically allocate memory.
//!
//! - `macros`
//!
//!   Enables macros that provide compile-time verification of values and intuitive syntax.
//!
//! - `formatting` (_implicitly enables `std`_)
//!
//!   Enables formatting of most structs.
//!
//! - `parsing`
//!
//!   Enables parsing of most structs.
//!
//! - `local-offset` (_implicitly enables `std`_)
//!
//!   This feature enables a number of methods that allow obtaining the system's UTC offset.
//!
//! - `large-dates`
//!
//!   By default, only years within the ±9999 range (inclusive) are supported. If you need support
//!   for years outside this range, consider enabling this feature; the supported range will be
//!   increased to ±999,999.
//!
//!   Note that enabling this feature has some costs, as it means forgoing some optimizations.
//!   Ambiguities may be introduced when parsing that would not otherwise exist.
//!
//!   If you are using this feature, **please leave a comment**
//!   [on this discussion](https://github.com/time-rs/time/discussions/306) with your use case. If
//!   there is not sufficient demand for this feature, it will be dropped in a future release.
//!
//! - `serde`
//!
//!   Enables [serde](https://docs.rs/serde) support for all types except [`Instant`].
//!
//! - `serde-human-readable` (_implicitly enables `serde`, `formatting`, and `parsing`_)
//!
//!   Allows serde representations to use a human-readable format. This is determined by the
//!   serializer, not the user. If this feature is not enabled or if the serializer requests a
//!   non-human-readable format, a format optimized for binary representation will be used.
//!
//!   Libraries should never enable this feature, as the decision of what format to use should be up
//!   to the user.
//!
//! - `serde-well-known` (_implicitly enables `serde/alloc`, `formatting`, and `parsing`_)
//!
//!   Enables support for serializing and deserializing well-known formats using serde's
//!   [`#[with]` attribute](https://serde.rs/field-attrs.html#with).
//!
//! - `rand`
//!
//!   Enables [rand](https://docs.rs/rand) support for all types.
//!
//! - `quickcheck` (_implicitly enables `alloc`_)
//!
//!   Enables [quickcheck](https://docs.rs/quickcheck) support for all types except [`Instant`].
//!
//! One pseudo-feature flag that is only available to end users is the `unsound_local_offset` cfg.
//! As the name indicates, using the feature is unsound, and [may cause unexpected segmentation
//! faults](https://github.com/time-rs/time/issues/293). Unlike other flags, this is deliberately
//! only available to end users; this is to ensure that a user doesn't have unsound behavior without
//! knowing it. To enable this behavior, you must use `RUSTFLAGS="--cfg unsound_local_offset" cargo
//! build` or similar. Note: This flag is _not tested anywhere_, including in the regular test of
//! the powerset of all feature flags. Use at your own risk. Without this flag, any method that
//! requires the local offset will return the `Err` variant.

#![doc(html_playground_url = "https://play.rust-lang.org")]
#![cfg_attr(__time_03_docs, feature(doc_cfg, doc_auto_cfg, doc_notable_trait))]
#![cfg_attr(
    __time_03_docs,
    deny(rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links)
)]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(
    anonymous_parameters,
    clippy::all,
    const_err,
    illegal_floating_point_literal_pattern,
    late_bound_lifetime_arguments,
    path_statements,
    patterns_in_fns_without_body,
    rust_2018_idioms,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unsafe_code,
    unsafe_op_in_unsafe_fn,
    unused_extern_crates
)]
#![warn(
    clippy::dbg_macro,
    clippy::decimal_literal_representation,
    clippy::get_unwrap,
    clippy::missing_docs_in_private_items,
    clippy::nursery,
    clippy::print_stdout,
    clippy::todo,
    clippy::unimplemented,
    clippy::unnested_or_patterns,
    clippy::unwrap_in_result,
    clippy::unwrap_used,
    clippy::use_debug,
    deprecated_in_future,
    missing_copy_implementations,
    missing_debug_implementations,
    unused_qualifications,
    variant_size_differences
)]
#![allow(clippy::redundant_pub_crate)]
#![doc(html_favicon_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/55999857")]
#![doc(test(attr(deny(warnings))))]

#[allow(unused_extern_crates)]
#[cfg(feature = "alloc")]
extern crate alloc;

// region: macros
/// Helper macro for easily implementing `OpAssign`.
macro_rules! __impl_assign {
    ($sym:tt $op:ident $fn:ident $target:ty : $($(#[$attr:meta])* $t:ty),+) => {$(
        #[allow(unused_qualifications)]
        $(#[$attr])*
        impl core::ops::$op<$t> for $target {
            fn $fn(&mut self, rhs: $t) {
                *self = *self $sym rhs;
            }
        }
    )+};
}

/// Implement `AddAssign` for the provided types.
macro_rules! impl_add_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(+ AddAssign add_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `SubAssign` for the provided types.
macro_rules! impl_sub_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(- SubAssign sub_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `MulAssign` for the provided types.
macro_rules! impl_mul_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(* MulAssign mul_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Implement `DivAssign` for the provided types.
macro_rules! impl_div_assign {
    ($target:ty : $($(#[$attr:meta])* $t:ty),+ $(,)?) => {
        __impl_assign!(/ DivAssign div_assign $target : $($(#[$attr])* $t),+);
    };
}

/// Division of integers, rounding the resulting value towards negative infinity.
macro_rules! div_floor {
    ($a:expr, $b:expr) => {{
        let _a = $a;
        let _b = $b;

        let (_quotient, _remainder) = (_a / _b, _a % _b);

        if (_remainder > 0 && _b < 0) || (_remainder < 0 && _b > 0) {
            _quotient - 1
        } else {
            _quotient
        }
    }};
}

/// Cascade an out-of-bounds value.
macro_rules! cascade {
    (@ordinal ordinal) => {};
    (@year year) => {};

    // Cascade an out-of-bounds value from "from" to "to".
    ($from:ident in $min:literal.. $max:literal => $to:tt) => {
        #[allow(unused_comparisons, unused_assignments)]
        if $from >= $max {
            $from -= $max - $min;
            $to += 1;
        } else if $from < $min {
            $from += $max - $min;
            $to -= 1;
        }
    };

    // Special case the ordinal-to-year cascade, as it has different behavior.
    ($ordinal:ident => $year:ident) => {
        // We need to actually capture the idents. Without this, macro hygiene causes errors.
        cascade!(@ordinal $ordinal);
        cascade!(@year $year);
        #[allow(unused_assignments)]
        if $ordinal > crate::util::days_in_year($year) {
            $year += 1;
            $ordinal = 1;
        } else if $ordinal == 0 {
            $year -= 1;
            $ordinal = crate::util::days_in_year($year);
        }
    };
}

/// Returns `Err(error::ComponentRange)` if the value is not in range.
macro_rules! ensure_value_in_range {
    ($value:ident in $start:expr => $end:expr) => {{
        let _start = $start;
        let _end = $end;
        #[allow(trivial_numeric_casts, unused_comparisons)]
        if $value < _start || $value > _end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: _start as _,
                maximum: _end as _,
                value: $value as _,
                conditional_range: false,
            });
        }
    }};

    ($value:ident conditionally in $start:expr => $end:expr) => {{
        let _start = $start;
        let _end = $end;
        #[allow(trivial_numeric_casts, unused_comparisons)]
        if $value < _start || $value > _end {
            return Err(crate::error::ComponentRange {
                name: stringify!($value),
                minimum: _start as _,
                maximum: _end as _,
                value: $value as _,
                conditional_range: true,
            });
        }
    }};
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but does not perform `.into()`. Because of this, it is
/// usable in `const` contexts.
macro_rules! const_try {
    ($e:expr) => {
        match $e {
            Ok(value) => value,
            Err(error) => return Err(error),
        }
    };
}

/// Try to unwrap an expression, returning if not possible.
///
/// This is similar to the `?` operator, but is usable in `const` contexts.
macro_rules! const_try_opt {
    ($e:expr) => {
        match $e {
            Some(value) => value,
            None => return None,
        }
    };
}
// endregion macros

mod date;
mod duration;
pub mod error;
pub mod ext;
#[cfg(any(feature = "formatting", feature = "parsing"))]
pub mod format_description;
#[cfg(feature = "formatting")]
pub mod formatting;
#[cfg(feature = "std")]
mod instant;
#[cfg(feature = "macros")]
pub mod macros;
mod month;
mod offset_date_time;
#[cfg(feature = "parsing")]
pub mod parsing;
mod primitive_date_time;
#[cfg(feature = "quickcheck")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "quickcheck")))]
mod quickcheck;
#[cfg(feature = "rand")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "rand")))]
mod rand;
#[cfg(feature = "serde")]
#[cfg_attr(__time_03_docs, doc(cfg(feature = "serde")))]
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub mod serde;
mod sys;
#[cfg(test)]
mod tests;
mod time;
mod utc_offset;
pub mod util;
mod weekday;

pub use crate::date::Date;
pub use crate::duration::Duration;
pub use crate::error::Error;
#[cfg(feature = "std")]
pub use crate::instant::Instant;
pub use crate::month::Month;
pub use crate::offset_date_time::OffsetDateTime;
pub use crate::primitive_date_time::PrimitiveDateTime;
pub use crate::time::Time;
pub use crate::utc_offset::UtcOffset;
pub use crate::weekday::Weekday;

/// An alias for [`std::result::Result`] with a generic error from the time crate.
pub type Result<T> = core::result::Result<T, Error>;
<|endoftext|>


<commit_before>#[test]
fn it_works() {
	let world = World::new_half_adder ();
}

// 2 billion junctions is good enough for now
type JunctionIndex = i32;
type ElementIndex = i32;
type OutputIndex = i8;
type Time = i64;
type Level = bool;

enum GateBehavior {
	Inverter,
	And,
	Xor,
}

// In the future, at time "time", junction "junction" will be set to level "level".
pub struct Delay {
	junction: JunctionIndex,
	level: Level,
	time: Time,
}

pub struct Wire {
	input: JunctionIndex,
	output: JunctionIndex,
	delay: Time,
}

pub struct Gate {
	inputs: Vec <JunctionIndex>,
	output: JunctionIndex,
	behavior: GateBehavior,
}

pub struct World {
	wires: Vec <Wire>,
	gates: Vec <Gate>,

	junctions: Vec <bool>,
	time: Time,
	delays: Vec <Delay>,
}

impl Wire {
	fn new (input: JunctionIndex, output: JunctionIndex, delay: Time) -> Wire {
		Wire {
			input: input,
			output: output,
			delay: delay,
		}
	}
}

impl World {
	fn new_half_adder () -> World {
		World {
			time: 0,
			delays: vec![],
			junctions: vec![false; 10],
			wires: vec![
				Wire::new (0, 1, 4),
				Wire::new (0, 5, 8),
				Wire::new (2, 3, 4),
				Wire::new (6, 7, 3),
				Wire::new (8, 4, 8),
				Wire::new (8, 9, 4),
			],
			gates: vec![
				Gate {
					inputs: vec![2, 5],
					output: 3,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![6, 10],
					output: 7,
					behavior: GateBehavior::Xor,
				},
			],
		}
	}
}<commit_msg>Fixing the destiny system which was not working at all<commit_after>#[test]
fn test_sorting () {
	let mut unsorted = vec! [3, 2, 1];

	let sorted = vec! [1, 2, 3];

	unsorted.sort_by (|a, b| a.cmp (b));

	assert_eq! (unsorted, sorted);
}

#[test]
pub fn it_works() {
	let mut world = World::new_half_adder ();
	println! ("Constructed world");
	// This has to be done for initialization, it should be automated
	world.step_gates ();

	world.step_to_settled ();

	assert_eq! (world.junctions [3], false);
	assert_eq! (world.junctions [7], false);

	world.delays.push (Delay {
		junction: 0,
		level: true,
		time: world.time,
	});

	world.step_to_settled ();

	assert_eq! (world.junctions [3], false);
	assert_eq! (world.junctions [7], true);

	world.delays.push (Delay {
		junction: 8,
		level: true,
		time: world.time,
	});

	world.step_to_settled ();

	assert_eq! (world.junctions [3], true);
	assert_eq! (world.junctions [7], false);

	world.delays.push (Delay {
		junction: 0,
		level: false,
		time: world.time,
	});

	world.step_to_settled ();

	assert_eq! (world.junctions [3], false);
	assert_eq! (world.junctions [7], true);
}

// 2 billion junctions is good enough for now
type JunctionIndex = usize;
type ElementIndex = u32;
type OutputIndex = u8;
type Time = i64;
type Level = bool;

enum GateBehavior {
	Inverter,
	And,
	Xor,
}

// In the future, at time "time", junction "junction" will be set to level "level".
#[derive (Clone, Copy)]
pub struct Delay {
	junction: JunctionIndex,
	level: Level,
	time: Time,
}

#[derive (Clone, Copy)]
pub struct Wire {
	input: JunctionIndex,
	output: JunctionIndex,
	delay: Time,
}

pub struct Gate {
	inputs: Vec <JunctionIndex>,
	output: JunctionIndex,
	behavior: GateBehavior,
}

pub struct World {
	wires: Vec <Wire>,
	gates: Vec <Gate>,

	junctions: Vec <bool>,
	time: Time,
	delays: Vec <Delay>,
}

impl Wire {
	fn new (input: JunctionIndex, output: JunctionIndex, delay: Time) -> Wire {
		Wire {
			input: input,
			output: output,
			delay: delay,
		}
	}
}

enum JunctionDestiny {
	Settled (Level),
	Eventually (Delay),
}

impl World {
	fn new_half_adder () -> World {
		World {
			time: 0,
			delays: vec![],
			junctions: vec![false; 10],
			wires: vec![
				Wire::new (0, 1, 4),
				Wire::new (0, 5, 8),
				Wire::new (2, 3, 4),
				Wire::new (6, 7, 3),
				Wire::new (8, 4, 8),
				Wire::new (8, 9, 4),
			],
			gates: vec![
				Gate {
					inputs: vec![1, 4],
					output: 2,
					behavior: GateBehavior::And,
				},
				Gate {
					inputs: vec![5, 9],
					output: 6,
					behavior: GateBehavior::Xor,
				},
			],
		}
	}

	fn is_settled (& self) -> bool {
		self.delays.len () == 0
	}

	fn sort_delays (&mut self) {
		// This step is just a safety since we should be insertion sorting the delays already
		self.delays.sort_by (|a, b| a.time.cmp (&b.time));
	}

	fn step_gates (&mut self) {
		let mut new_delays = Vec::<Delay>::new ();

		// TODO: Optimize to only touch gates whose inputs have changed
		for gate in self.gates.iter () {
			let inputs: Vec <bool> = gate.inputs.iter ().map (|i| self.junctions [*i]).collect ();

			let output = match gate.behavior {
				GateBehavior::And => inputs.iter ().fold (true, |sum, a| sum && *a),
				GateBehavior::Xor => inputs.iter ().fold (false, |sum, a| sum ^ *a),
				GateBehavior::Inverter => inputs [0],
			};

			let destiny = self.get_junction_destiny (gate.output);
			let destinyLevel = match destiny {
				JunctionDestiny::Settled (level) => level,
				JunctionDestiny::Eventually (delay) => delay.level,
			};

			if destinyLevel != output {
				new_delays.push (Delay {
					junction: gate.output,
					time: self.time,
					level: output,
				});

				println! ("Gate {} set to {}", gate.output, output);
			}
		};

		for delay in new_delays {
			self.delays.push (delay);
		}

		// TODO: Proper insertion sorting
		self.sort_delays ();
	}

	fn get_junction_destiny (& self, junction: JunctionIndex) -> JunctionDestiny {
		if self.delays.len () > 0 {
			//println! ("Delays:");

			for i in 0 .. self.delays.len () {
				let delay: Delay = self.delays [self.delays.len () - i - 1];

				//println! ("At {} junction {} will be {}", delay.time, delay.junction, delay.level);

				if delay.junction == junction {
					return JunctionDestiny::Eventually (delay);
				}
			}
		}

		JunctionDestiny::Settled (self.junctions [junction])
	}

	fn step_wires (&mut self) {
		for wire in self.wires.iter () {
			let input = self.junctions [wire.input];

			// Don't push redundant delays
			let destiny = self.get_junction_destiny (wire.output);
			let destinyLevel = match destiny {
				JunctionDestiny::Settled (level) => level,
				JunctionDestiny::Eventually (delay) => delay.level,
			};

			if input != destinyLevel {
				self.delays.push (Delay {
					junction: wire.output,
					time: self.time + wire.delay,
					level: input,
				});

				let destiny_type = match destiny {
					JunctionDestiny::Settled (_) => "Settled",
					JunctionDestiny::Eventually (_) => "Eventually",
				};

				//println! ("Wire {} set to {}", wire.output, input);
			}
		};

		// TODO: Proper insertion sorting
		self.sort_delays ();
	}

	fn propagate_delays (&mut self) {
		let next_time = self.delays [0].time;

		for delay in self.delays.iter () {
			if delay.time == next_time {
				self.junctions [delay.junction] = delay.level;

				println! ("Junction {} set to {}", delay.junction, delay.level);
			}
		}

		self.delays.retain (|delay| delay.time > next_time);

		self.time = next_time;
	}

	fn step (&mut self) {
		if self.is_settled () {
			return;
		}

		self.sort_delays ();

		self.propagate_delays ();

		self.step_gates ();
		self.step_wires ();
	}

	fn step_to_settled (&mut self) {
		while ! self.is_settled () {
			self.step ();
		}
	}
}<|endoftext|>