<commit_before>pub mod resource;
pub mod worker;

use village::resource::*;
use village::worker::*;
use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;

pub type VillageRef = Rc<RefCell<Village>>;

pub type CheckForWorkerDeath = fn(&Worker) -> bool;

pub struct Village {
    pub stockpile: HashMap<ResourceType, u32>,

    workers: Vec<Worker>,
    worker_id_counter: u32,
    resources: Vec<Resource>,
    resource_id_counter: u32,

    check_for_worker_death: CheckForWorkerDeath,
}

impl Village {
    pub fn new(check_for_worker_death: CheckForWorkerDeath) -> Village {
        let mut village = Village {
            stockpile: HashMap::new(),
            workers: vec!(),
            worker_id_counter: 0,
            resources: vec!(),
            resource_id_counter: 0,
            check_for_worker_death: check_for_worker_death,
        };

        //add each resource type to the stockpile
        for resource_type in ResourceType::iterator() {
            village.stockpile.insert(*resource_type, 0);
        }

        village
    }

    /// Adds a new Worker instance to this Village.
    /// Worker id values start at 1 and auto increment in subsequent invocations
    /// Returns the id of the Worker instance
    pub fn create_worker(&mut self) -> WorkerId {
        self.worker_id_counter += 1;
        self.workers.push(Worker::new(self.worker_id_counter));

        self.worker_id_counter
    }

    /// Adds a new Resource instance to this Village.
    /// Resource id values start at 1 and auto increment in subsequent invocations
    /// Returns the id of the Resource instance
    pub fn create_resource(&mut self, resource_type: ResourceType) -> ResourceId {
        self.resource_id_counter += 1;

        self.resources.push(Resource {
            resource_type: resource_type,
            resource_id: self.resource_id_counter,
        });

        self.resource_id_counter
    }

    /// Assigns a worker to an object
    /// Passing in a resource id of value 0 will cause the worker to be ideal
    pub fn assign_worker(&mut self, worker_id: WorkerId, resource_id: ResourceId) {
        if let Some(w) = self.workers.iter_mut().find(|w| w.worker_id == worker_id) {
            if resource_id == 0 {
                w.assigned_resource = 0;
            } else if let Some(r) = self.resources.iter().find(|r| r.resource_id == resource_id) {
                w.assigned_resource = r.resource_id;
            }
        }
    }

    pub fn resource(&self, resource_id: ResourceId) -> Option<&Resource> {
        self.resources.iter().find(|r| r.resource_id == resource_id)
    }

    pub fn resources_of_type(&self, resource_type: ResourceType) -> Vec<&Resource> {
        self.resources.iter()
            .filter(|r| r.resource_type == resource_type)
            .collect()
    }

    pub fn resources(&self) -> &Vec<Resource> {
        &self.resources
    }

    pub fn idle_worker_count(&self) -> u32 {
        self.workers.iter().filter(|w| w.assigned_resource == 0).count() as u32
    }

    pub fn worker(&self, worker_id: WorkerId) -> Option<&Worker> {
        self.workers.iter().find(|w| w.worker_id == worker_id)
    }

    pub fn workers_on_resource(&self, resource_id: u32) -> Vec<&Worker> {
        self.workers.iter().filter(|w| w.assigned_resource == resource_id).collect()
    }

    pub fn simulate(&mut self) {
        for worker in self.workers.iter() {
            let resource_type : ResourceType;

            if let Some(r) = self.resource(worker.assigned_resource) {
                resource_type = r.resource_type;
            } else {
                continue;
            }

            *self.stockpile.get_mut(&resource_type).unwrap() += 1;
        }

        for worker in self.workers.iter_mut() {
            worker.age += 1;
            worker.is_alive = !(self.check_for_worker_death)(&worker);
        }

        // remove workers not alive
        self.workers.retain(|ref w| w.is_alive);
    }
}

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

    fn default_village() -> Village {
        Village::new(|w: &Worker| false)
    }

    #[test]
    fn create_resources() {
        let mut v = default_village();
        v.create_resource(ResourceType::Gold);
        v.create_resource(ResourceType::Gold);
        v.create_resource(ResourceType::Wood);

        assert_eq!(3, v.resources().len());
    }

    #[test]
    fn assign_worker_to_resource() {
        let mut v = default_village();
        let w1 = v.create_worker();
        let r1 = v.create_resource(ResourceType::Gold);

        v.assign_worker(w1, r1);

        assert_eq!(1, v.workers_on_resource(r1).len());
        assert_eq!(0, v.idle_worker_count());
    }

    #[test]
    fn unassign_worker_from_resource() {
        let mut v = default_village();
        let w1 = v.create_worker();
        let r1 = v.create_resource(ResourceType::Gold);

        v.assign_worker(w1, r1);
        v.assign_worker(w1, 0);

        assert_eq!(0, v.workers_on_resource(r1).len());
        assert_eq!(1, v.idle_worker_count());
    }

    #[test]
    fn stockpile_starts_empty() {
        let v = default_village();
        let value = v.stockpile.get(&ResourceType::Food);

        assert_eq!(0, *value.unwrap());
    }

    #[test]
    fn simulate_collect_resources() {
        let mut v = default_village();
        let r1 = v.create_resource(ResourceType::Wood);
        let w1 = v.create_worker();
        let w2 = v.create_worker();

        v.assign_worker(w1, r1);
        v.assign_worker(w2, r1);
        v.simulate();

        assert_eq!(2, *v.stockpile.get(&ResourceType::Wood).unwrap());
    }

    #[test]
    fn simulate_increase_worker_age() {
        let mut v = default_village();
        let w1 = v.create_worker();

        v.simulate();

        assert_eq!(1, v.worker(w1).unwrap().age);
    }

    #[test]
    fn simulate_increase_worker_age_multiple() {
        let mut v = default_village();
        let w1 = v.create_worker();
        let w2 = v.create_worker();

        v.simulate();
        v.simulate();

        assert_eq!(2, v.worker(w1).unwrap().age);
        assert_eq!(2, v.worker(w2).unwrap().age);
    }

    #[test]
    fn simulate_worker_death() {
        let mut v = Village::new(|w| w.worker_id == 1);
        let w1 = v.create_worker();
        let w2 = v.create_worker();

        v.simulate();

        assert!(v.worker(w1).is_none());
        assert!(v.worker(w2).is_some());
    }

    #[test]
    fn get_resources_by_type() {
        let mut v = default_village();
        v.create_resource(ResourceType::Gold);
        v.create_resource(ResourceType::Wood);
        v.create_resource(ResourceType::Wood);

        assert_eq!(1, v.resources_of_type(ResourceType::Gold).len());
        assert_eq!(2, v.resources_of_type(ResourceType::Wood).len());
        assert_eq!(0, v.resources_of_type(ResourceType::Stone).len());
        assert_eq!(0, v.resources_of_type(ResourceType::Food).len());
    }
}<commit_msg>Added return error on assign worker<commit_after>pub mod resource;
pub mod worker;

use village::resource::*;
use village::worker::*;
use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;

pub type VillageRef = Rc<RefCell<Village>>;

pub type CheckForWorkerDeath = fn(&Worker) -> bool;

pub struct Village {
    pub stockpile: HashMap<ResourceType, u32>,

    workers: Vec<Worker>,
    worker_id_counter: u32,
    resources: Vec<Resource>,
    resource_id_counter: u32,

    check_for_worker_death: CheckForWorkerDeath,
}

impl Village {
    pub fn new(check_for_worker_death: CheckForWorkerDeath) -> Village {
        let mut village = Village {
            stockpile: HashMap::new(),
            workers: vec!(),
            worker_id_counter: 0,
            resources: vec!(),
            resource_id_counter: 0,
            check_for_worker_death: check_for_worker_death,
        };

        //add each resource type to the stockpile
        for resource_type in ResourceType::iterator() {
            village.stockpile.insert(*resource_type, 0);
        }

        village
    }

    /// Adds a new Worker instance to this Village.
    /// Worker id values start at 1 and auto increment in subsequent invocations
    /// Returns the id of the Worker instance
    pub fn create_worker(&mut self) -> WorkerId {
        self.worker_id_counter += 1;
        self.workers.push(Worker::new(self.worker_id_counter));

        self.worker_id_counter
    }

    /// Adds a new Resource instance to this Village.
    /// Resource id values start at 1 and auto increment in subsequent invocations
    /// Returns the id of the Resource instance
    pub fn create_resource(&mut self, resource_type: ResourceType) -> ResourceId {
        self.resource_id_counter += 1;

        self.resources.push(Resource {
            resource_type: resource_type,
            resource_id: self.resource_id_counter,
        });

        self.resource_id_counter
    }

    /// Assigns a worker to an object
    /// Passing in a resource id of value 0 will cause the worker to be ideal
    pub fn assign_worker(&mut self, worker_id: WorkerId, resource_id: ResourceId) -> Result<(), &'static str> {
        if let Some(w) = self.workers.iter_mut().find(|w| w.worker_id == worker_id) {
            if resource_id == 0 {
                w.assigned_resource = 0;
            } else if let Some(r) = self.resources.iter().find(|r| r.resource_id == resource_id) {
                w.assigned_resource = r.resource_id;
            } else {
               return Err("Invalid Resource ID");
            }
        }
        else {
            return Err("Invalid Worker ID");
        }
        Ok(())
    }

    pub fn resource(&self, resource_id: ResourceId) -> Option<&Resource> {
        self.resources.iter().find(|r| r.resource_id == resource_id)
    }

    pub fn resources_of_type(&self, resource_type: ResourceType) -> Vec<&Resource> {
        self.resources.iter()
            .filter(|r| r.resource_type == resource_type)
            .collect()
    }

    pub fn resources(&self) -> &Vec<Resource> {
        &self.resources
    }

    pub fn idle_worker_count(&self) -> u32 {
        self.workers.iter().filter(|w| w.assigned_resource == 0).count() as u32
    }

    pub fn worker(&self, worker_id: WorkerId) -> Option<&Worker> {
        self.workers.iter().find(|w| w.worker_id == worker_id)
    }

    pub fn workers_on_resource(&self, resource_id: u32) -> Vec<&Worker> {
        self.workers.iter().filter(|w| w.assigned_resource == resource_id).collect()
    }

    pub fn simulate(&mut self) {
        for worker in self.workers.iter() {
            let resource_type : ResourceType;

            if let Some(r) = self.resource(worker.assigned_resource) {
                resource_type = r.resource_type;
            } else {
                continue;
            }

            *self.stockpile.get_mut(&resource_type).unwrap() += 1;
        }

        for worker in self.workers.iter_mut() {
            worker.age += 1;
            worker.is_alive = !(self.check_for_worker_death)(&worker);
        }

        // remove workers not alive
        self.workers.retain(|ref w| w.is_alive);
    }
}

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

    fn default_village() -> Village {
        Village::new(|w: &Worker| false)
    }

    #[test]
    fn create_resources() {
        let mut v = default_village();
        v.create_resource(ResourceType::Gold);
        v.create_resource(ResourceType::Gold);
        v.create_resource(ResourceType::Wood);

        assert_eq!(3, v.resources().len());
    }

    #[test]
    fn assign_worker_to_resource() {
        let mut v = default_village();
        let w1 = v.create_worker();
        let r1 = v.create_resource(ResourceType::Gold);

        v.assign_worker(w1, r1);

        assert_eq!(1, v.workers_on_resource(r1).len());
        assert_eq!(0, v.idle_worker_count());
    }

    #[test]
    fn unassign_worker_from_resource() {
        let mut v = default_village();
        let w1 = v.create_worker();
        let r1 = v.create_resource(ResourceType::Gold);

        v.assign_worker(w1, r1);
        v.assign_worker(w1, 0);

        assert_eq!(0, v.workers_on_resource(r1).len());
        assert_eq!(1, v.idle_worker_count());
    }

    #[test]
    fn assign_worker_to_resource_invalid_worker_id() {
        let mut v = default_village();
        let r1 = v.create_resource(ResourceType::Gold);

        assert!(v.assign_worker(1, r1).is_err());
    }

    #[test]
    fn assign_worker_to_resource_invalid_resource_id() {
        let mut v = default_village();
        let w1 = v.create_worker();

        assert!(v.assign_worker(w1, 1).is_err());
    }

    #[test]
    fn stockpile_starts_empty() {
        let v = default_village();
        let value = v.stockpile.get(&ResourceType::Food);

        assert_eq!(0, *value.unwrap());
    }

    #[test]
    fn simulate_collect_resources() {
        let mut v = default_village();
        let r1 = v.create_resource(ResourceType::Wood);
        let w1 = v.create_worker();
        let w2 = v.create_worker();

        v.assign_worker(w1, r1);
        v.assign_worker(w2, r1);
        v.simulate();

        assert_eq!(2, *v.stockpile.get(&ResourceType::Wood).unwrap());
    }

    #[test]
    fn simulate_increase_worker_age() {
        let mut v = default_village();
        let w1 = v.create_worker();

        v.simulate();

        assert_eq!(1, v.worker(w1).unwrap().age);
    }

    #[test]
    fn simulate_increase_worker_age_multiple() {
        let mut v = default_village();
        let w1 = v.create_worker();
        let w2 = v.create_worker();

        v.simulate();
        v.simulate();

        assert_eq!(2, v.worker(w1).unwrap().age);
        assert_eq!(2, v.worker(w2).unwrap().age);
    }

    #[test]
    fn simulate_worker_death() {
        let mut v = Village::new(|w| w.worker_id == 1);
        let w1 = v.create_worker();
        let w2 = v.create_worker();

        v.simulate();

        assert!(v.worker(w1).is_none());
        assert!(v.worker(w2).is_some());
    }

    #[test]
    fn get_resources_by_type() {
        let mut v = default_village();
        v.create_resource(ResourceType::Gold);
        v.create_resource(ResourceType::Wood);
        v.create_resource(ResourceType::Wood);

        assert_eq!(1, v.resources_of_type(ResourceType::Gold).len());
        assert_eq!(2, v.resources_of_type(ResourceType::Wood).len());
        assert_eq!(0, v.resources_of_type(ResourceType::Stone).len());
        assert_eq!(0, v.resources_of_type(ResourceType::Food).len());
    }
}<|endoftext|>


<commit_before>extern crate wiringpi;

use wiringpi::pin::Value::{High, Low};
use wiringpi::time::delay;

fn main() {
    //Setup WiringPi with its own pin numbering order
    let pi = wiringpi::setup();

    //Use WiringPi pin 0 as output
    let pin = pi.output_pin(0);

    loop {
        //Set pin 0 to high and wait one second
        pin.digital_write(High);
        delay(1000);

        //Set pin 0 to low and wait one second
        pin.digital_write(Low);
        delay(1000);
    }
}<commit_msg>Updated example<commit_after>extern crate wiringpi;

use wiringpi::pin::Value::{High, Low};
use std::time::Duration;
use std::thread;

fn main() {
    //Setup WiringPi with its own pin numbering order
    let pi = wiringpi::setup();

    //Use WiringPi pin 0 as output
    let pin = pi.output_pin(0);

    loop {
        //Set pin 0 to high and wait one second
        pin.digital_write(High);
        thread::sleep(Duration::from_millis(1000));

        //Set pin 0 to low and wait one second
        pin.digital_write(Low);
        thread::sleep(Duration::from_millis(1000));
    }
}
<|endoftext|>


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

use crate::{account_address::AccountAddress, event::EventKey};
use anyhow::Result;
use move_core_types::move_resource::MoveResource;
use serde::{Deserialize, Serialize};

/// Struct that represents a NewBlockEvent.
#[derive(Debug, Serialize, Deserialize)]
pub struct NewBlockEvent {
    round: u64,
    proposer: AccountAddress,
    previous_block_votes: Vec<AccountAddress>,
    time_micro_seconds: u64,
}

impl NewBlockEvent {
    pub fn round(&self) -> u64 {
        self.round
    }

    pub fn proposer(&self) -> AccountAddress {
        self.proposer
    }

    pub fn proposed_time(&self) -> u64 {
        self.time_micro_seconds
    }

    pub fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
        lcs::from_bytes(bytes).map_err(Into::into)
    }

    pub fn event_key() -> EventKey {
        crate::block_metadata::new_block_event_key()
    }
}

impl MoveResource for NewBlockEvent {
    const MODULE_NAME: &'static str = "LibraBlock";
    const STRUCT_NAME: &'static str = "NewBlockEvent";
}
<commit_msg>Removing event_key from types/src/account_config/events/new_block.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_address::AccountAddress;
use anyhow::Result;
use move_core_types::move_resource::MoveResource;
use serde::{Deserialize, Serialize};

/// Struct that represents a NewBlockEvent.
#[derive(Debug, Serialize, Deserialize)]
pub struct NewBlockEvent {
    round: u64,
    proposer: AccountAddress,
    previous_block_votes: Vec<AccountAddress>,
    time_micro_seconds: u64,
}

impl NewBlockEvent {
    pub fn round(&self) -> u64 {
        self.round
    }

    pub fn proposer(&self) -> AccountAddress {
        self.proposer
    }

    pub fn proposed_time(&self) -> u64 {
        self.time_micro_seconds
    }

    pub fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
        lcs::from_bytes(bytes).map_err(Into::into)
    }
}

impl MoveResource for NewBlockEvent {
    const MODULE_NAME: &'static str = "LibraBlock";
    const STRUCT_NAME: &'static str = "NewBlockEvent";
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

fn main() {
  let stdin = io::stdin();
  let line = stdin.lock().lines().next().unwrap().unwrap();
  let line2 = stdin.lock().lines().next().unwrap().unwrap();
    // Removes the new lines /n from the end
  let num_str1 = line.trim();
  let num_str2 = line2.trim();
    // Convert to an int32
  let num1 = num_str1.parse::<i32>().unwrap();
  let num2 = num_str2.parse::<i32>().unwrap();
    // Print the sum
    println!("{}", num1 + num2 );
}
<commit_msg>Updated to better version... does not actually work on hackerrank :|<commit_after>use std::io;
use std::io::prelude::*;

fn main() {

	let stdin = io::stdin();

	let a: i32 = stdin.lock().lines().next().unwrap().unwrap().trim().parse().unwrap();
	let b: i32 = stdin.lock().lines().next().unwrap().unwrap().trim().parse().unwrap();

	println!("{}", a + b);

}
<|endoftext|>


<commit_before>//! This module implements minimal run-time feature detection for x86.
//!
//! The features are detected using the `detect_features` function below. This function
//! uses the CPUID instruction to read the feature flags from the CPU and encodes them in
//! an `usize` where each bit position represents whether a feature is available (bit is set)
//! or unavaiable (bit is cleared).
//!
//! The enum `__Feature` is used to map bit positions to feature names, and the
//! the `__unstable_detect_feature!` macro is used to map string literals (e.g.
//! "avx") to these bit positions (e.g. `__Feature::avx`).
//!
//!
//! The run-time feature detection is performed by the
//! `__unstable_detect_feature(__Feature) -> bool` function. On its first call,
//! this functions queries the CPU for the available features and stores them in
//! a global `AtomicUsize` variable. The query is performed by just checking whether the
//! feature bit in this global variable is set or cleared.
use ::std::sync::atomic::{AtomicUsize, Ordering};

/// This macro maps the string-literal feature names to values of the
/// `__Feature` enum at compile-time. The feature names used are the same as
/// those of rustc `target_feature` and `cfg_target_feature` features.
///
/// PLESE: do not use this, it is an implementation detail subjected to change.
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
    ("sse") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse{}) };
    ("sse2") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse2{}) };
    ("sse3") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse3{}) };
    ("ssse3") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::ssse3{}) };
    ("sse4.1") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse4_1{}) };
    ("sse4.2") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse4_2{}) };
    ("avx") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::avx{}) };
    ("avx2") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::avx2{}) };
    ("fma") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::fma{}) };
    ("bmi") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::bmi{}) };
    ("bmi2") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::bmi2{}) };
    ("abm") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::abm{}) };
    ("lzcnt") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::abm{}) };
    ("tbm") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::tbm{}) };
    ("popcnt") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::popcnt{}) };
    ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}

/// X86 CPU Feature enum. Each variant denotes a position in a bitset for a
/// particular feature.
///
/// PLEASE: do not use this, it is an implementation detail subject to change.
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[repr(u8)]
pub enum __Feature {
    /// SSE (Streaming SIMD Extensions)
    sse = 0,
    /// SSE2 (Streaming SIMD Extensions 2)
    sse2 = 1,
    /// SSE3 (Streaming SIMD Extensions 3)
    sse3 = 2,
    /// SSSE3 (Supplemental Streaming SIMD Extensions 3)
    ssse3 = 3,
    /// SSE4.1 (Streaming SIMD Extensions 4.1)
    sse4_1 = 4,
    /// SSE4.2 (Streaming SIMD Extensions 4.2)
    sse4_2 = 5,
    /// AVX (Advanced Vector Extensions)
    avx = 6,
    /// AVX2 (Advanced Vector Extensions 2)
    avx2 = 7,
    /// FMA (Fused Multiply Add)
    fma = 8,
    /// BMI1 (Bit Manipulation Instructions 1)
    bmi = 9,
    /// BMI1 (Bit Manipulation Instructions 2)
    bmi2 = 10,
    /// ABM (Advanced Bit Manipulation) on AMD / LZCNT (Leading Zero Count) on Intel
    abm = 11,
    /// TBM (Trailing Bit Manipulation)
    tbm = 12,
    /// POPCNT (Population Count)
    popcnt = 13,

    #[doc(hidden)]
    __NonExhaustive
}

fn set_bit(x: usize, bit: u32) -> usize {
    debug_assert!(32 > bit);
    x | 1 << bit
}

fn test_bit(x: usize, bit: u32) -> bool {
    debug_assert!(32 > bit);
    x & (1 << bit) != 0
}

fn inv_test_bit(v: usize, idx: u32) -> bool {
    debug_assert!(32 > idx);
    ((v >> idx) & 1) != 0
}

/// Run-time feature detection on x86 works by using the CPUID instruction.
///
/// The [CPUID Wikipedia page](https://en.wikipedia.org/wiki/CPUID) contains all
/// the information about which flags to set to query which values, and in which
/// registers these are reported.
///
/// The definitive references are:
/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2: Instruction Set Reference, A-Z](http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf).
/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and System Instructions](http://support.amd.com/TechDocs/24594.pdf).
///
fn detect_features() -> usize {
    let ebx;
    let ecx;
    let edx;

    unsafe {
        /// To obtain all feature flags we need two CPUID queries:

        /// 1. EAX=1, ECX=0: Queries "Processor Info and Feature Bits"
        /// This gives us most of the CPU features in ECX and EDX (see below),
        asm!("cpuid"
             : "={ecx}"(ecx), "={edx}"(edx)
             : "{eax}"(0x00000001u32), "{ecx}"(0 as u32)
             : :);

        /// 2. EAX=7, ECX=0: Queries "Extended Features"
        /// This gives us information about bmi,bmi2, and avx2 support (see below).
        asm!("cpuid"
             : "={ebx}"(ebx)
             : "{eax}"(0x00000007u32), "{ecx}"(0 as u32)
             : :);
    }

    let mut value: usize = 0;

    // CPUID call with EAX=7, ECX=0 => Extended Features in EBX and ECX (unneeded):
    if inv_test_bit(ebx, 3) { value = set_bit(value, __Feature::bmi as u32); }
    if inv_test_bit(ebx, 5) { value = set_bit(value, __Feature::avx2 as u32); }
    if inv_test_bit(ebx, 8) { value = set_bit(value, __Feature::bmi2 as u32); }

    // CPUID call with EAX=1 => feature bits in ECX and EDX:
    if inv_test_bit(ecx, 0) { value = set_bit(value, __Feature::sse3 as u32); }
    if inv_test_bit(ecx, 5) { value = set_bit(value, __Feature::abm as u32); }
    if inv_test_bit(ecx, 9) { value = set_bit(value, __Feature::ssse3 as u32); }
    if inv_test_bit(ecx, 12) { value = set_bit(value, __Feature::fma as u32); }
    if inv_test_bit(ecx, 19) { value = set_bit(value, __Feature::sse4_1 as u32); }
    if inv_test_bit(ecx, 20) { value = set_bit(value, __Feature::sse4_2 as u32); }
    if inv_test_bit(ecx, 21) { value = set_bit(value, __Feature::tbm as u32); }
    if inv_test_bit(ecx, 23) { value = set_bit(value, __Feature::popcnt as u32); }
    if inv_test_bit(ecx, 28) { value = set_bit(value, __Feature::avx as u32); }

    if inv_test_bit(edx, 25) { value = set_bit(value, __Feature::sse as u32); }
    if inv_test_bit(edx, 26) { value = set_bit(value, __Feature::sse2 as u32); }

    value
}

/// This global variable is a bitset used to cache the features supported by the
/// CPU.
static FEATURES: AtomicUsize = AtomicUsize::new(::std::usize::MAX);

/// Performs run-time feature detection.
///
/// On its first invocation, it detects the CPU features and caches them in the
/// `FEATURES` global variable as an `AtomicUsize`.
///
/// It uses the `__Feature` variant to index into this variable as a bitset. If
/// the bit is set, the feature is enabled, and otherwise it is disabled.
///
/// PLEASE: do not use this, it is an implementation detail subject to change.
#[doc(hidden)]
pub fn __unstable_detect_feature(x: __Feature) -> bool {
    if FEATURES.load(Ordering::Relaxed)  == ::std::usize::MAX {
        FEATURES.store(detect_features(), Ordering::Relaxed);
    }
    test_bit(FEATURES.load(Ordering::Relaxed), x as u32)
}

#[cfg(test)]
mod tests {
    #[test]
    fn runtime_detection_x86_nocapture() {
        println!("sse: {:?}", cfg_feature_enabled!("sse"));
        println!("sse2: {:?}", cfg_feature_enabled!("sse2"));
        println!("sse3: {:?}", cfg_feature_enabled!("sse3"));
        println!("ssse3: {:?}", cfg_feature_enabled!("ssse3"));
        println!("sse4.1: {:?}", cfg_feature_enabled!("sse4.1"));
        println!("sse4.2: {:?}", cfg_feature_enabled!("sse4.2"));
        println!("avx: {:?}", cfg_feature_enabled!("avx"));
        println!("avx2: {:?}", cfg_feature_enabled!("avx2"));
        println!("abm: {:?}", cfg_feature_enabled!("abm"));
        println!("bmi: {:?}", cfg_feature_enabled!("bmi"));
        println!("bmi2: {:?}", cfg_feature_enabled!("bmi2"));
        println!("tbm: {:?}", cfg_feature_enabled!("tbm"));
        println!("popcnt: {:?}", cfg_feature_enabled!("popcnt"));
        println!("lzcnt: {:?}", cfg_feature_enabled!("lzcnt"));
        println!("fma: {:?}", cfg_feature_enabled!("fma"));
    }
}
<commit_msg>remove explicit discriminant values<commit_after>//! This module implements minimal run-time feature detection for x86.
//!
//! The features are detected using the `detect_features` function below. This function
//! uses the CPUID instruction to read the feature flags from the CPU and encodes them in
//! an `usize` where each bit position represents whether a feature is available (bit is set)
//! or unavaiable (bit is cleared).
//!
//! The enum `__Feature` is used to map bit positions to feature names, and the
//! the `__unstable_detect_feature!` macro is used to map string literals (e.g.
//! "avx") to these bit positions (e.g. `__Feature::avx`).
//!
//!
//! The run-time feature detection is performed by the
//! `__unstable_detect_feature(__Feature) -> bool` function. On its first call,
//! this functions queries the CPU for the available features and stores them in
//! a global `AtomicUsize` variable. The query is performed by just checking whether the
//! feature bit in this global variable is set or cleared.
use ::std::sync::atomic::{AtomicUsize, Ordering};

/// This macro maps the string-literal feature names to values of the
/// `__Feature` enum at compile-time. The feature names used are the same as
/// those of rustc `target_feature` and `cfg_target_feature` features.
///
/// PLESE: do not use this, it is an implementation detail subjected to change.
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
    ("sse") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse{}) };
    ("sse2") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse2{}) };
    ("sse3") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse3{}) };
    ("ssse3") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::ssse3{}) };
    ("sse4.1") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse4_1{}) };
    ("sse4.2") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::sse4_2{}) };
    ("avx") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::avx{}) };
    ("avx2") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::avx2{}) };
    ("fma") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::fma{}) };
    ("bmi") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::bmi{}) };
    ("bmi2") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::bmi2{}) };
    ("abm") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::abm{}) };
    ("lzcnt") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::abm{}) };
    ("tbm") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::tbm{}) };
    ("popcnt") => { $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::popcnt{}) };
    ($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}

/// X86 CPU Feature enum. Each variant denotes a position in a bitset for a
/// particular feature.
///
/// PLEASE: do not use this, it is an implementation detail subject to change.
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[repr(u8)]
pub enum __Feature {
    /// SSE (Streaming SIMD Extensions)
    sse,
    /// SSE2 (Streaming SIMD Extensions 2)
    sse2,
    /// SSE3 (Streaming SIMD Extensions 3)
    sse3,
    /// SSSE3 (Supplemental Streaming SIMD Extensions 3)
    ssse3,
    /// SSE4.1 (Streaming SIMD Extensions 4.1)
    sse4_1,
    /// SSE4.2 (Streaming SIMD Extensions 4.2)
    sse4_2,
    /// AVX (Advanced Vector Extensions)
    avx,
    /// AVX2 (Advanced Vector Extensions 2)
    avx2,
    /// FMA (Fused Multiply Add)
    fma,
    /// BMI1 (Bit Manipulation Instructions 1)
    bmi,
    /// BMI1 (Bit Manipulation Instructions 2)
    bmi2,
    /// ABM (Advanced Bit Manipulation) on AMD / LZCNT (Leading Zero Count) on Intel
    abm,
    /// TBM (Trailing Bit Manipulation)
    tbm,
    /// POPCNT (Population Count)
    popcnt,

    #[doc(hidden)]
    __NonExhaustive
}

fn set_bit(x: usize, bit: u32) -> usize {
    debug_assert!(32 > bit);
    x | 1 << bit
}

fn test_bit(x: usize, bit: u32) -> bool {
    debug_assert!(32 > bit);
    x & (1 << bit) != 0
}

fn inv_test_bit(v: usize, idx: u32) -> bool {
    debug_assert!(32 > idx);
    ((v >> idx) & 1) != 0
}

/// Run-time feature detection on x86 works by using the CPUID instruction.
///
/// The [CPUID Wikipedia page](https://en.wikipedia.org/wiki/CPUID) contains all
/// the information about which flags to set to query which values, and in which
/// registers these are reported.
///
/// The definitive references are:
/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2: Instruction Set Reference, A-Z](http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf).
/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and System Instructions](http://support.amd.com/TechDocs/24594.pdf).
///
fn detect_features() -> usize {
    let ebx;
    let ecx;
    let edx;

    unsafe {
        /// To obtain all feature flags we need two CPUID queries:

        /// 1. EAX=1, ECX=0: Queries "Processor Info and Feature Bits"
        /// This gives us most of the CPU features in ECX and EDX (see below),
        asm!("cpuid"
             : "={ecx}"(ecx), "={edx}"(edx)
             : "{eax}"(0x00000001u32), "{ecx}"(0 as u32)
             : :);

        /// 2. EAX=7, ECX=0: Queries "Extended Features"
        /// This gives us information about bmi,bmi2, and avx2 support (see below).
        asm!("cpuid"
             : "={ebx}"(ebx)
             : "{eax}"(0x00000007u32), "{ecx}"(0 as u32)
             : :);
    }

    let mut value: usize = 0;

    // CPUID call with EAX=7, ECX=0 => Extended Features in EBX and ECX (unneeded):
    if inv_test_bit(ebx, 3) { value = set_bit(value, __Feature::bmi as u32); }
    if inv_test_bit(ebx, 5) { value = set_bit(value, __Feature::avx2 as u32); }
    if inv_test_bit(ebx, 8) { value = set_bit(value, __Feature::bmi2 as u32); }

    // CPUID call with EAX=1 => feature bits in ECX and EDX:
    if inv_test_bit(ecx, 0) { value = set_bit(value, __Feature::sse3 as u32); }
    if inv_test_bit(ecx, 5) { value = set_bit(value, __Feature::abm as u32); }
    if inv_test_bit(ecx, 9) { value = set_bit(value, __Feature::ssse3 as u32); }
    if inv_test_bit(ecx, 12) { value = set_bit(value, __Feature::fma as u32); }
    if inv_test_bit(ecx, 19) { value = set_bit(value, __Feature::sse4_1 as u32); }
    if inv_test_bit(ecx, 20) { value = set_bit(value, __Feature::sse4_2 as u32); }
    if inv_test_bit(ecx, 21) { value = set_bit(value, __Feature::tbm as u32); }
    if inv_test_bit(ecx, 23) { value = set_bit(value, __Feature::popcnt as u32); }
    if inv_test_bit(ecx, 28) { value = set_bit(value, __Feature::avx as u32); }

    if inv_test_bit(edx, 25) { value = set_bit(value, __Feature::sse as u32); }
    if inv_test_bit(edx, 26) { value = set_bit(value, __Feature::sse2 as u32); }

    value
}

/// This global variable is a bitset used to cache the features supported by the
/// CPU.
static FEATURES: AtomicUsize = AtomicUsize::new(::std::usize::MAX);

/// Performs run-time feature detection.
///
/// On its first invocation, it detects the CPU features and caches them in the
/// `FEATURES` global variable as an `AtomicUsize`.
///
/// It uses the `__Feature` variant to index into this variable as a bitset. If
/// the bit is set, the feature is enabled, and otherwise it is disabled.
///
/// PLEASE: do not use this, it is an implementation detail subject to change.
#[doc(hidden)]
pub fn __unstable_detect_feature(x: __Feature) -> bool {
    if FEATURES.load(Ordering::Relaxed)  == ::std::usize::MAX {
        FEATURES.store(detect_features(), Ordering::Relaxed);
    }
    test_bit(FEATURES.load(Ordering::Relaxed), x as u32)
}

#[cfg(test)]
mod tests {
    #[test]
    fn runtime_detection_x86_nocapture() {
        println!("sse: {:?}", cfg_feature_enabled!("sse"));
        println!("sse2: {:?}", cfg_feature_enabled!("sse2"));
        println!("sse3: {:?}", cfg_feature_enabled!("sse3"));
        println!("ssse3: {:?}", cfg_feature_enabled!("ssse3"));
        println!("sse4.1: {:?}", cfg_feature_enabled!("sse4.1"));
        println!("sse4.2: {:?}", cfg_feature_enabled!("sse4.2"));
        println!("avx: {:?}", cfg_feature_enabled!("avx"));
        println!("avx2: {:?}", cfg_feature_enabled!("avx2"));
        println!("abm: {:?}", cfg_feature_enabled!("abm"));
        println!("bmi: {:?}", cfg_feature_enabled!("bmi"));
        println!("bmi2: {:?}", cfg_feature_enabled!("bmi2"));
        println!("tbm: {:?}", cfg_feature_enabled!("tbm"));
        println!("popcnt: {:?}", cfg_feature_enabled!("popcnt"));
        println!("lzcnt: {:?}", cfg_feature_enabled!("lzcnt"));
        println!("fma: {:?}", cfg_feature_enabled!("fma"));
    }
}
<|endoftext|>


<commit_before>use AsMutLua;
use AsLua;

use Push;
use PushGuard;
use LuaRead;
use Void;

macro_rules! tuple_impl {
    ($ty:ident) => (
        impl<'lua, LU, $ty> Push<LU> for ($ty,) where LU: AsMutLua<'lua>, $ty: Push<LU> {
            type Err = <$ty as Push<LU>>::Err;

            #[inline]
            fn push_to_lua(self, lua: LU) -> Result<PushGuard<LU>, (Self::Err, LU)> {
                self.0.push_to_lua(lua)
            }
        }

        impl<'lua, LU, $ty> LuaRead<LU> for ($ty,) where LU: AsMutLua<'lua>, $ty: LuaRead<LU> {
            #[inline]
            fn lua_read_at_position(lua: LU, index: i32) -> Result<($ty,), LU> {
                LuaRead::lua_read_at_position(lua, index).map(|v| (v,))
            }
        }
    );

    ($first:ident, $($other:ident),+) => (
        #[allow(non_snake_case)]
        impl<'lua, LU, $first: for<'a> Push<&'a mut LU>, $($other: for<'a> Push<&'a mut LU>),+>
            Push<LU> for ($first, $($other),+) where LU: AsMutLua<'lua>
        {
            type Err = Void;      // TODO: wrong

            #[inline]
            fn push_to_lua(self, mut lua: LU) -> Result<PushGuard<LU>, (Self::Err, LU)> {
                match self {
                    ($first, $($other),+) => {
                        let mut total = match $first.push_to_lua(&mut lua) {
                            Ok(pushed) => pushed.forget(),
                            Err(_) => panic!()      // TODO: wrong
                        };

                        $(
                            total += match $other.push_to_lua(&mut lua) {
                                Ok(pushed) => pushed.forget(),
                                Err(_) => panic!()      // TODO: wrong
                            };
                        )+

                        let raw_lua = lua.as_lua();
                        Ok(PushGuard { lua: lua, size: total, raw_lua: raw_lua })
                    }
                }
            }
        }

        // TODO: what if T or U are also tuples? indices won't match
        #[allow(unused_assignments)]
        #[allow(non_snake_case)]
        impl<'lua, LU, $first: for<'a> LuaRead<&'a mut LU>, $($other: for<'a> LuaRead<&'a mut LU>),+>
            LuaRead<LU> for ($first, $($other),+) where LU: AsLua<'lua>
        {
            #[inline]
            fn lua_read_at_position(mut lua: LU, index: i32) -> Result<($first, $($other),+), LU> {
                let mut i = index;

                let $first: $first = match LuaRead::lua_read_at_position(&mut lua, i) {
                    Ok(v) => v,
                    Err(_) => return Err(lua)
                };

                i += 1;

                $(
                    let $other: $other = match LuaRead::lua_read_at_position(&mut lua, i) {
                        Ok(v) => v,
                        Err(_) => return Err(lua)
                    };
                    i += 1;
                )+

                Ok(($first, $($other),+))

            }
        }

        tuple_impl!($($other),+);
    );
}

tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M);
<commit_msg>Add PushOne impl for (T,) where T: PushOne<commit_after>use AsMutLua;
use AsLua;

use Push;
use PushOne;
use PushGuard;
use LuaRead;
use Void;

macro_rules! tuple_impl {
    ($ty:ident) => (
        impl<'lua, LU, $ty> Push<LU> for ($ty,) where LU: AsMutLua<'lua>, $ty: Push<LU> {
            type Err = <$ty as Push<LU>>::Err;

            #[inline]
            fn push_to_lua(self, lua: LU) -> Result<PushGuard<LU>, (Self::Err, LU)> {
                self.0.push_to_lua(lua)
            }
        }

        impl<'lua, LU, $ty> PushOne<LU> for ($ty,) where LU: AsMutLua<'lua>, $ty: PushOne<LU> {
        }

        impl<'lua, LU, $ty> LuaRead<LU> for ($ty,) where LU: AsMutLua<'lua>, $ty: LuaRead<LU> {
            #[inline]
            fn lua_read_at_position(lua: LU, index: i32) -> Result<($ty,), LU> {
                LuaRead::lua_read_at_position(lua, index).map(|v| (v,))
            }
        }
    );

    ($first:ident, $($other:ident),+) => (
        #[allow(non_snake_case)]
        impl<'lua, LU, $first: for<'a> Push<&'a mut LU>, $($other: for<'a> Push<&'a mut LU>),+>
            Push<LU> for ($first, $($other),+) where LU: AsMutLua<'lua>
        {
            type Err = Void;      // TODO: wrong

            #[inline]
            fn push_to_lua(self, mut lua: LU) -> Result<PushGuard<LU>, (Self::Err, LU)> {
                match self {
                    ($first, $($other),+) => {
                        let mut total = match $first.push_to_lua(&mut lua) {
                            Ok(pushed) => pushed.forget(),
                            Err(_) => panic!()      // TODO: wrong
                        };

                        $(
                            total += match $other.push_to_lua(&mut lua) {
                                Ok(pushed) => pushed.forget(),
                                Err(_) => panic!()      // TODO: wrong
                            };
                        )+

                        let raw_lua = lua.as_lua();
                        Ok(PushGuard { lua: lua, size: total, raw_lua: raw_lua })
                    }
                }
            }
        }

        // TODO: what if T or U are also tuples? indices won't match
        #[allow(unused_assignments)]
        #[allow(non_snake_case)]
        impl<'lua, LU, $first: for<'a> LuaRead<&'a mut LU>, $($other: for<'a> LuaRead<&'a mut LU>),+>
            LuaRead<LU> for ($first, $($other),+) where LU: AsLua<'lua>
        {
            #[inline]
            fn lua_read_at_position(mut lua: LU, index: i32) -> Result<($first, $($other),+), LU> {
                let mut i = index;

                let $first: $first = match LuaRead::lua_read_at_position(&mut lua, i) {
                    Ok(v) => v,
                    Err(_) => return Err(lua)
                };

                i += 1;

                $(
                    let $other: $other = match LuaRead::lua_read_at_position(&mut lua, i) {
                        Ok(v) => v,
                        Err(_) => return Err(lua)
                    };
                    i += 1;
                )+

                Ok(($first, $($other),+))

            }
        }

        tuple_impl!($($other),+);
    );
}

tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M);
<|endoftext|>


<commit_before>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(pat_decl, pats) => fail!(~":V"),
        ast::ListPattern(pats) => {
            match *val {
                types::List(vals) => {
                    if vals.len() < pats.len() {
                        false
                    } else {
                        match pats[pats.len() - 1] {
                            ast::ManyPattern => {
                                // pattern match with a spread argument
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() - 1 {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            },
                            _ => {
                                if vals.len() > pats.len() {
                                    // no spread argument, :(
                                    false
                                } else {
                                    // pattern match with a full pattern list
                                    let mut ok = true;
                                    let mut i = 0;
                                    while i < pats.len() {
                                        ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                        if !ok { break; };
                                        i += 1;
                                    }
                                    ok
                                }
                            }
                        }
                    }
                },
                _ => false
            }
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match failed"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                fail!(fmt!("%? in %s:%u", f, frame.file, frame.lineno))
            }
        }
    }
}
<commit_msg>formatting<commit_after>use ast;
use lexer;
use parser;

use interp::env;
use interp::types;

use core::hashmap::linear;
use core::to_bytes;

/*
 * aster - AST EvaulatoR
 *
 * aster evaluates a Prismo program via reduction of the AST.
 *
 * "It's pretty terrible."
 * -- Tony, 2013
 */

impl to_bytes::IterBytes for ast::RecordName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::RecordName(n, s) => (n, s).iter_bytes(lsb0, f)
        }
    }
}

impl to_bytes::IterBytes for ast::DottedName {
    fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) {
        match self {
            &ast::DottedName(s) => s.iter_bytes(lsb0, f)
        }
    }
}

pub struct Interp {
    record_types: @mut linear::LinearMap<@ast::RecordName, @ast::RecordDeclaration>,
    import_paths: @[Path],
    root: @mut env::Env<Interp>,
    argv: @[@str],
    filename: @str,
    current_frame: @mut option::Option<@mut Frame>
}

pub impl Interp {
    pub fn new(import_paths: @[Path], argv: @[@str], filename: @str) -> Interp {
        Interp {
            record_types: @mut linear::LinearMap::new(),
            import_paths: import_paths,
            root: @mut env::Env::new(),
            argv: argv,
            filename: filename,
            current_frame: @mut option::None
        }
    }
}

fn wind(interp: @mut Interp, env: @mut env::Env<Interp>, lineno: uint) -> @mut Frame {
    // allocate a new frame
    let frame = @mut Frame::new(interp, env, interp.filename, lineno);
    interp.current_frame = @mut option::Some(frame);
    frame
}

fn unwind(interp: @mut Interp) -> () {
    interp.current_frame = match *interp.current_frame {
        option::None => @mut option::None,
        option::Some(frame) => frame.parent
    };
}

pub struct Frame {
    parent: @mut option::Option<@mut Frame>,
    env: @mut env::Env<Interp>,
    file: @str,
    lineno: uint,
    exception: @mut option::Option<@mut types::Val<Interp>>
}

pub impl Frame {
    pub fn new(interp: @mut Interp, env: @mut env::Env<Interp>, file: @str, lineno: uint) -> Frame {
        Frame {
            parent: interp.current_frame,
            env: env,
            file: file,
            lineno: lineno,
            exception: @mut option::None
        }
    }
}

pub fn import_module(interp: @mut Interp, name: &ast::DottedName, qualified: bool) -> () {
    let module_parts = (**name).to_owned().map(|x| (*x).to_owned());
    let mut parts = copy module_parts;

    vec::reverse(parts);
    let module_name = copy parts[0];
    let filename = fmt!("%s.pr", module_name);
    parts = vec::tail(parts).to_owned();
    vec::reverse(parts);

    let mut found = false;
    let mut paths = interp.import_paths.to_owned();

    for paths.each_mut |import_path| {
        // make a path inside the import path and check if that exists
        let base_path = (copy *import_path).push_many(parts);
        let path = base_path.push(filename);

        if os::path_exists(&path) {
            // make a copy of the import paths then give them to a new sub-interpreter
            let mut import_paths1 = interp.import_paths.to_owned();
            import_paths1.unshift(base_path);

            let interp1 = @mut Interp::new(at_vec::from_owned(import_paths1), interp.argv, path.to_str().to_managed());

            // run the file in the sub-interpreter
            run_file(interp1, &path);

            if qualified {
                let module_name = ast::Sym(module_name.to_managed());

                // qualified imports symbols from child interpreter into a module
                env::declare(interp.root, &module_name,
                             @mut types::Module(interp1.root.vars));

                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(match *k {
                        @ast::RecordName(modu, name) => @ast::RecordName(@ast::DottedName(**modu + [module_name]), name)
                    }, *interp1.record_types.find(k).unwrap());
                }
            } else {
                // otherwise we just plop all the symbols in
                for interp1.root.vars.each_key |k| {
                    env::declare(interp.root, k, *interp1.root.vars.find(k).unwrap());
                }

                // import record types
                for interp1.record_types.each_key |k| {
                    interp.record_types.insert(*k, *interp1.record_types.find(k).unwrap());
                }
            }

            found = true;
            break;
        }
    };

    if !found {
        fail!(fmt!("couldn't import module %s", str::connect(module_parts, ".")))
    };
}

fn unify_pattern_basic(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::Pat, val: @mut types::Val<Interp>) -> bool {
    // perform pattern matching of basic patterns -- if a match fails, we leave all the symbols in
    // scope and not care. this is pretty bad.
    match *pat {
        ast::AnyPattern => true,
        ast::ManyPattern => false,
        ast::UnitPattern => match *val {
            types::Unit => true,
            _ => false
        },
        ast::LiteralPattern(lit) => *val == types:: gen_lit(lit),
        ast::SymbolPattern(sym) => {
            env::declare(env, &sym, val);
            true
        },
        ast::BoundPattern(sym, pat) => {
            let r = unify_pattern_basic(interp, env, pat, val);
            env::declare(env, &sym, val);
            r
        },
        ast::DisjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) || unify_pattern_basic(interp, env, pat2, val)
        },
        ast::ConjunctivePattern(pat1, pat2) => {
            unify_pattern_basic(interp, env, pat1, val) && unify_pattern_basic(interp, env, pat2, val)
        },
        ast::RecordPattern(pat_decl, pats) => fail!(~":V"),
        ast::ListPattern(pats) => match *val {
            types::List(vals) => {
                if vals.len() < pats.len() {
                    false
                } else {
                    match pats[pats.len() - 1] {
                        ast::ManyPattern => {
                            // pattern match with a spread argument
                            let mut ok = true;
                            let mut i = 0;
                            while i < pats.len() - 1 {
                                ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                if !ok { break; };
                                i += 1;
                            }
                            ok
                        },
                        _ => {
                            if vals.len() > pats.len() {
                                // no spread argument, :(
                                false
                            } else {
                                // pattern match with a full pattern list
                                let mut ok = true;
                                let mut i = 0;
                                while i < pats.len() {
                                    ok = unify_pattern_basic(interp, env, &pats[i], vals[i]);
                                    if !ok { break; };
                                    i += 1;
                                }
                                ok
                            }
                        }
                    }
                }
            },
            _ => false
        }
    }
}

fn unify_pattern_let(interp: @mut Interp, env: @mut env::Env<Interp>, pat: &ast::LetPat, val: @mut types::Val<Interp>) -> bool {
    match *pat {
        ast::BasicPattern(pat) => unify_pattern_basic(interp, env, &pat, val),
        _ => fail!(~":V")
    }
}

fn eval_exp(interp: @mut Interp, env: @mut env::Env<Interp>, exp: &ast::Exp) -> types::Val<Interp> {
    let frame = interp.current_frame.unwrap();

    let r = match exp.exp {
        ast::UnitExpression => types::Unit,
        ast::LiteralExpression(l) => types::gen_lit(l),
        ast::LambdaExpression(pat, exp) => types::Function(@[types::Fun {
            pattern: pat,
            body: exp,
            env: env
        }]),
        ast::ListExpression(exps) => {
            let mut vals = @[];

            for exps.each |exp| {
                vals += [@mut eval_exp(interp, env, exp)];
                if !frame.exception.is_none() {
                    return types::Unit;
                }
            }

            types::List(vals)
        },
        ast::SymbolExpression(sym) => {
            match env::find(env, &sym) {
                option::Some(x) => types::Unit,
                option::None => {
                    frame.exception = @mut option::Some(@mut types::String(fmt!("symbol `%s` not found in scope", *sym).to_managed()));
                    types::Unit
                }
            }
        },
        _ => fail!(~":V")
    };

    r
}

fn exec_stmt(interp: @mut Interp, env: @mut env::Env<Interp>, stmt: &ast::Stmt) -> () {
    let frame = interp.current_frame.unwrap();

    match stmt.stmt {
        ast::LetBindingStatement(pat, exp) => {
            if !unify_pattern_let(interp, env, &pat, @mut eval_exp(interp, env, &exp)) {
                // uh oh, we need to throw an exception and unwind
                frame.exception = @mut option::Some(@mut types::String(@"pattern match failed"));
            }
        },
        ast::ExpressionStatement(exp) => { eval_exp(interp, env, &exp); }
    };
}

pub fn run_file(interp: @mut Interp, path: &Path) -> () {
    match io::file_reader(path) {
        result::Ok(r) => {
            let tokens = lexer::lex(r);
            let program = parser::parse(tokens);
            run(interp, program);
        },
        result::Err(f) => fail!(f)
    }
}

pub fn run(interp: @mut Interp, prog: ast::Program) -> () {
    for prog.imports.each |imp| {
        import_module(interp, &imp.module, imp.qualified);
    }

    for prog.records.each |rec| {
        interp.record_types.insert(@rec.name, @*rec);
    }

    for prog.body.each |stmt| {
        let mut frame = wind(interp, interp.root, stmt.lineno);

        exec_stmt(interp, interp.root, stmt);

        match *frame.exception {
            option::None => unwind(interp),
            option::Some(f) => {
                fail!(fmt!("%? in %s:%u", f, frame.file, frame.lineno))
            }
        }
    }
}
<|endoftext|>


<commit_before>use orbtk::prelude::*;
use std::cell::Cell;

use euc::{buffer::Buffer2d, rasterizer, Pipeline, Target};
use vek::*;

// Cube is copied from euc spinning_cube example
// https://github.com/zesterer/euc/blob/master/examples/spinning_cube.rs
struct Cube<'a> {
    mvp: Mat4<f32>,
    positions: &'a [Vec4<f32>],
}

impl<'a> Pipeline for Cube<'a> {
    type Vertex = (usize, Rgba<f32>);
    type VsOut = Rgba<f32>;
    type Pixel = u32;

    #[inline(always)]
    fn vert(&self, (v_index, v_color): &Self::Vertex) -> ([f32; 4], Self::VsOut) {
        ((self.mvp * self.positions[*v_index]).into_array(), *v_color)
    }

    #[inline(always)]
    fn frag(&self, v_color: &Self::VsOut) -> Self::Pixel {
        let bytes = v_color.map(|e| (e * 255.0) as u8).into_array();
        (bytes[2] as u32) << 0
            | (bytes[1] as u32) << 8
            | (bytes[0] as u32) << 16
            | (bytes[3] as u32) << 24
    }
}

#[derive(Clone, Default, PartialEq)]
struct CubePipeline {
    spin: Cell<f32>,
}

impl render::RenderPipeline for CubePipeline {
    fn box_eq(&self, other: &dyn Any) -> bool {
        other.downcast_ref::<Self>().map_or(false, |a| self == a)
    }
    fn as_any(&self) -> &dyn Any {
        self
    }
    fn clone_box(&self) -> Box<dyn render::RenderPipeline> {
        Box::new(self.clone())
    }
    fn draw_pipeline(&self, image: &mut render::Image) {
        let mut color = Buffer2d::new([image.width() as usize, image.height() as usize], 0);
        let mut depth = Buffer2d::new([image.width() as usize, image.height() as usize], 1.0);

        let mvp = Mat4::perspective_fov_rh_no(
            1.3,
            image.width() as f32,
            image.height() as f32,
            0.01,
            100.0,
        ) * Mat4::translation_3d(Vec3::new(0.0, 0.0, -2.0))
            * Mat4::<f32>::scaling_3d(0.4)
            * Mat4::rotation_x((self.spin.get() * 0.002) * 8.0)
            * Mat4::rotation_y((self.spin.get() as f32 * 0.004).cos() * 4.0)
            * Mat4::rotation_z((self.spin.get() as f32 * 0.008).sin() * 2.0);

        Cube {
            mvp,
            positions: &[
                Vec4::new(-1.0, -1.0, -1.0, 1.0), // 0
                Vec4::new(-1.0, -1.0, 1.0, 1.0),  // 1
                Vec4::new(-1.0, 1.0, -1.0, 1.0),  // 2
                Vec4::new(-1.0, 1.0, 1.0, 1.0),   // 3
                Vec4::new(1.0, -1.0, -1.0, 1.0),  // 4
                Vec4::new(1.0, -1.0, 1.0, 1.0),   // 5
                Vec4::new(1.0, 1.0, -1.0, 1.0),   // 6
                Vec4::new(1.0, 1.0, 1.0, 1.0),    // 7
            ],
        }
        .draw::<rasterizer::Triangles<_, rasterizer::BackfaceCullingEnabled>, _>(
            &[
                // -x
                (0, Rgba::green()),
                (3, Rgba::blue()),
                (2, Rgba::red()),
                (0, Rgba::green()),
                (1, Rgba::red()),
                (3, Rgba::blue()),
                // +x
                (7, Rgba::blue()),
                (4, Rgba::green()),
                (6, Rgba::red()),
                (5, Rgba::red()),
                (4, Rgba::green()),
                (7, Rgba::blue()),
                // -y
                (5, Rgba::blue()),
                (0, Rgba::red()),
                (4, Rgba::green()),
                (1, Rgba::green()),
                (0, Rgba::red()),
                (5, Rgba::blue()),
                // +y
                (2, Rgba::red()),
                (7, Rgba::blue()),
                (6, Rgba::green()),
                (2, Rgba::red()),
                (3, Rgba::green()),
                (7, Rgba::blue()),
                // -z
                (0, Rgba::red()),
                (6, Rgba::green()),
                (4, Rgba::blue()),
                (0, Rgba::red()),
                (2, Rgba::blue()),
                (6, Rgba::green()),
                // +z
                (7, Rgba::green()),
                (1, Rgba::red()),
                (5, Rgba::blue()),
                (3, Rgba::blue()),
                (1, Rgba::red()),
                (7, Rgba::green()),
            ],
            &mut color,
            &mut depth,
        );

        image.draw(color.as_ref());
    }
}

#[derive(Default)]
pub struct MainViewState {
    cube_spin: Cell<f32>,
}

impl MainViewState {
    fn spin(&self) {
        self.cube_spin.set(self.cube_spin.get() + 16.0);
    }
}

impl State for MainViewState {
    fn update(&self, context: &mut Context<'_>) {
        if let Some(cube) = context
            .widget()
            .get_mut::<RenderPipeline>()
            .0
            .as_any()
            .downcast_ref::<CubePipeline>()
        {
            cube.spin.set(self.cube_spin.get());
        }
    }
}

widget!(
    MainView<MainViewState> {
         cube_pipeline: RenderPipeline
    }
);

impl Template for MainView {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let state = self.clone_state();
        self.name("MainView")
            .cube_pipeline(RenderPipeline(Box::new(CubePipeline::default())))
            .child(
                Grid::create()
                    .rows(Rows::create().row("*").row("*").build())
                    .child(
                        TextBlock::create()
                            .attach(GridRow(0))
                            .text("Canvas (3D pipeline)")
                            .selector(SelectorValue::new().with("text-block").class("h1"))
                            .margin(4.0)
                            .build(ctx),
                    )
                    .child(Canvas::create().attach(GridRow(0)).pipeline(id).build(ctx))
                    .child(
                        Button::create()
                            .text("spin cube")
                            .vertical_alignment("End")
                            .attach(GridRow(0))
                            .margin(4.0)
                            .on_click(move |_| {
                                state.spin();
                                true
                            })
                            .build(ctx),
                    )
                    .child(
                        TextBlock::create()
                            .attach(GridRow(1))
                            .text("Canvas (2D pipeline)")
                            .selector(SelectorValue::new().with("text-block").class("h1"))
                            .margin(4.0)
                            .build(ctx),
                    )
                    .child(Canvas::create().attach(GridRow(1)).build(ctx))
                    .build(ctx),
            )
    }
}

fn main() {
    // use this only if you want to run it as web application.
    orbtk::initialize();

    Application::new()
        .window(|ctx| {
            Window::create()
                .title("OrbTk - canvas example")
                .position((100.0, 100.0))
                .size(420.0, 730.0)
                .child(MainView::create().build(ctx))
                .build(ctx)
        })
        .run();
}
<commit_msg>Canvas update.<commit_after>use orbtk::prelude::*;
use std::cell::Cell;

use euc::{buffer::Buffer2d, rasterizer, Pipeline, Target};
use vek::*;

// Cube is copied from euc spinning_cube example
// https://github.com/zesterer/euc/blob/master/examples/spinning_cube.rs
struct Cube<'a> {
    mvp: Mat4<f32>,
    positions: &'a [Vec4<f32>],
}

impl<'a> Pipeline for Cube<'a> {
    type Vertex = (usize, Rgba<f32>);
    type VsOut = Rgba<f32>;
    type Pixel = u32;

    #[inline(always)]
    fn vert(&self, (v_index, v_color): &Self::Vertex) -> ([f32; 4], Self::VsOut) {
        ((self.mvp * self.positions[*v_index]).into_array(), *v_color)
    }

    #[inline(always)]
    fn frag(&self, v_color: &Self::VsOut) -> Self::Pixel {
        let bytes = v_color.map(|e| (e * 255.0) as u8).into_array();
        (bytes[2] as u32) << 0
            | (bytes[1] as u32) << 8
            | (bytes[0] as u32) << 16
            | (bytes[3] as u32) << 24
    }
}

#[derive(Clone, Default, PartialEq)]
struct CubePipeline {
    spin: Cell<f32>,
}

impl render::RenderPipeline for CubePipeline {
    fn box_eq(&self, other: &dyn Any) -> bool {
        other.downcast_ref::<Self>().map_or(false, |a| self == a)
    }
    fn as_any(&self) -> &dyn Any {
        self
    }
    fn clone_box(&self) -> Box<dyn render::RenderPipeline> {
        Box::new(self.clone())
    }
    fn draw_pipeline(&self, image: &mut render::Image) {
        let mut color = Buffer2d::new([image.width() as usize, image.height() as usize], 0);
        let mut depth = Buffer2d::new([image.width() as usize, image.height() as usize], 1.0);

        let mvp = Mat4::perspective_fov_rh_no(
            1.3,
            image.width() as f32,
            image.height() as f32,
            0.01,
            100.0,
        ) * Mat4::translation_3d(Vec3::new(0.0, 0.0, -2.0))
            * Mat4::<f32>::scaling_3d(0.4)
            * Mat4::rotation_x((self.spin.get() * 0.002) * 8.0)
            * Mat4::rotation_y((self.spin.get() as f32 * 0.004).cos() * 4.0)
            * Mat4::rotation_z((self.spin.get() as f32 * 0.008).sin() * 2.0);

        Cube {
            mvp,
            positions: &[
                Vec4::new(-1.0, -1.0, -1.0, 1.0), // 0
                Vec4::new(-1.0, -1.0, 1.0, 1.0),  // 1
                Vec4::new(-1.0, 1.0, -1.0, 1.0),  // 2
                Vec4::new(-1.0, 1.0, 1.0, 1.0),   // 3
                Vec4::new(1.0, -1.0, -1.0, 1.0),  // 4
                Vec4::new(1.0, -1.0, 1.0, 1.0),   // 5
                Vec4::new(1.0, 1.0, -1.0, 1.0),   // 6
                Vec4::new(1.0, 1.0, 1.0, 1.0),    // 7
            ],
        }
        .draw::<rasterizer::Triangles<_, rasterizer::BackfaceCullingEnabled>, _>(
            &[
                // -x
                (0, Rgba::green()),
                (3, Rgba::blue()),
                (2, Rgba::red()),
                (0, Rgba::green()),
                (1, Rgba::red()),
                (3, Rgba::blue()),
                // +x
                (7, Rgba::blue()),
                (4, Rgba::green()),
                (6, Rgba::red()),
                (5, Rgba::red()),
                (4, Rgba::green()),
                (7, Rgba::blue()),
                // -y
                (5, Rgba::blue()),
                (0, Rgba::red()),
                (4, Rgba::green()),
                (1, Rgba::green()),
                (0, Rgba::red()),
                (5, Rgba::blue()),
                // +y
                (2, Rgba::red()),
                (7, Rgba::blue()),
                (6, Rgba::green()),
                (2, Rgba::red()),
                (3, Rgba::green()),
                (7, Rgba::blue()),
                // -z
                (0, Rgba::red()),
                (6, Rgba::green()),
                (4, Rgba::blue()),
                (0, Rgba::red()),
                (2, Rgba::blue()),
                (6, Rgba::green()),
                // +z
                (7, Rgba::green()),
                (1, Rgba::red()),
                (5, Rgba::blue()),
                (3, Rgba::blue()),
                (1, Rgba::red()),
                (7, Rgba::green()),
            ],
            &mut color,
            &mut depth,
        );

        image.draw(color.as_ref());
    }
}

#[derive(Default)]
pub struct MainViewState {
    cube_spin: Cell<f32>,
}

impl MainViewState {
    fn spin(&self) {
        self.cube_spin.set(self.cube_spin.get() + 16.0);
    }
}

impl State for MainViewState {
    fn update(&self, context: &mut Context<'_>) {
        if let Some(cube) = context
            .widget()
            .get_mut::<RenderPipeline>()
            .0
            .as_any()
            .downcast_ref::<CubePipeline>()
        {
            cube.spin.set(self.cube_spin.get());
        }
    }
}

widget!(
    MainView<MainViewState> {
         cube_pipeline: RenderPipeline
    }
);

impl Template for MainView {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let state = self.clone_state();
        self.name("MainView")
            .cube_pipeline(RenderPipeline(Box::new(CubePipeline::default())))
            .child(
                Grid::create()
                    .rows(Rows::create().row("*").row("*").build())
                    .child(
                        TextBlock::create()
                            .attach(GridRow(0))
                            .text("Canvas (euc crate pipeline)")
                            .selector(SelectorValue::new().with("text-block").class("h1"))
                            .margin(4.0)
                            .build(ctx),
                    )
                    .child(Canvas::create().attach(GridRow(0)).pipeline(id).build(ctx))
                    .child(
                        Button::create()
                            .text("spin cube")
                            .vertical_alignment("End")
                            .attach(GridRow(0))
                            .margin(4.0)
                            .on_click(move |_| {
                                state.spin();
                                true
                            })
                            .build(ctx),
                    )
                    .child(
                        TextBlock::create()
                            .attach(GridRow(1))
                            .text("Canvas (OrbTk 2D pipeline)")
                            .selector(SelectorValue::new().with("text-block").class("h1"))
                            .margin(4.0)
                            .build(ctx),
                    )
                    .child(Canvas::create().attach(GridRow(1)).build(ctx))
                    .build(ctx),
            )
    }
}

fn main() {
    // use this only if you want to run it as web application.
    orbtk::initialize();

    Application::new()
        .window(|ctx| {
            Window::create()
                .title("OrbTk - canvas example")
                .position((100.0, 100.0))
                .size(420.0, 730.0)
                .child(MainView::create().build(ctx))
                .build(ctx)
        })
        .run();
}
<|endoftext|>