<commit_before>//! Thread-local storage for JavaScript threads.
//!
//! At runtime, an instance of a Node.js addon can contain its own local storage,
//! which can then be shared and accessed as needed from Rust in a Neon module. This can
//! be useful for setting up long-lived state that needs to be shared between calls
//! of an addon's APIs.
//!
//! For example, an addon may wish to track the [thread ID][threadId] of each of its
//! instances:
//!
//! ```
//! # use neon::prelude::*;
//! # use neon::thread::LocalKey;
//! static THREAD_ID: LocalKey<u32> = LocalKey::new();
//!
//! pub fn thread_id<'cx, C: Context<'cx>>(cx: &mut C) -> NeonResult<u32> {
//!     THREAD_ID.get_or_try_init(cx, |cx| {
//!         let global = cx.global();
//!         let require: Handle<JsFunction> = global.get(cx, "require")?;
//!         let worker: Handle<JsObject> = require.call_with(cx)
//!             .arg(cx.string("node:worker_threads"))
//!             .apply(cx)?;
//!         let thread_id: Handle<JsNumber> = worker.get(cx, "threadId")?;
//!         Ok(thread_id.value(cx) as u32)
//!     }).cloned()
//! }
//! ```
//!
//! ### The Addon Lifecycle
//!
//! For some use cases, a single shared global constant stored in a `static` variable
//! might be sufficient:
//!
//! ```
//! static MY_CONSTANT: &'static str = "hello Neon";
//! ```
//!
//! This variable will be allocated when the addon is first loaded into the Node.js
//! process. This works fine for single-threaded applications, or global immutable
//! data.
//!
//! However, since the addition of [worker threads][workers] in Node v10,
//! modules can be instantiated multiple times in a single Node process. This means
//! that while the dynamically-loaded binary library (i.e., the Rust implementation of
//! the addon) is only loaded once in the running process, but its [`#[main]`](neon::main) function
//! is executed multiple times with distinct module objects, once per application thread:
//!
//! ![The Node.js addon lifecycle, described in detail below.][lifecycle]
//!
//! This means that any thread-local data needs to be initialized separately for each
//! instance of the addon. This module provides a simple container type, [`LocalKey`](LocalKey),
//! for allocating and initializing thread-local data. (Technically, this data is stored in the
//! addon's [module instance][environment], which is equivalent to being thread-local.)
//!
//! A common example is when an addon needs to maintain a reference to a JavaScript value. References cannot
//! be used across separate threads. The constructor for the datatype can be [rooted](crate::handle::Root) and
//! saved in thread-local storage:
//!
//! ```
//! # use neon::prelude::*;
//! # use neon::thread::LocalKey;
//! # fn initialize_my_datatype<'cx, C: Context<'cx>>(cx: &mut C) -> JsResult<'cx, JsFunction> { unimplemented!() }
//! static MY_CONSTRUCTOR: LocalKey<Root<JsFunction>> = LocalKey::new();
//!
//! pub fn my_constructor<'cx, C: Context<'cx>>(cx: &mut C) -> JsResult<'cx, JsFunction> {
//!     let constructor = MY_CONSTRUCTOR.get_or_try_init(cx, |cx| {
//!         let constructor: Handle<JsFunction> = initialize_my_datatype(cx)?;
//!         Ok(constructor.root(cx))
//!     })?;
//!     Ok(constructor.to_inner(cx))
//! }
//! ```
//!
//! Notice that if this code were implemented without a `LocalKey`, it would fail whenever
//! one thread stores an instance of the constructor and a different thread attempts to
//! access it with the call to [`to_inner()`](crate::handle::Root::to_inner).
//!
//! ### When to Use Thread-Local Storage
//!
//! Single-threaded applications don't generally need to worry about thread-local data.
//! There are two cases where Neon apps should consider storing static data in a
//! `LocalKey` storage cell:
//!
//! - **Multi-threaded applications:** If your Node application uses the `Worker`
//!   API, you'll want to store any static data that might get access from multiple
//!   threads in thread-local data.
//! - **Libraries:** If your addon is part of a library that could be used by multiple
//!   applications, you'll want to store static data in thread-local data in case the
//!   addon ends up instantiated by multiple threads in some future application.
//!
//! ### Why Not Use Standard TLS?
//!
//! Because the JavaScript engine may not tie JavaScript threads 1:1 to system threads,
//! it is recommended to use this module instead of the Rust standard thread-local storage
//! when tying data to a JavaScript thread.
//!
//! [environment]: https://nodejs.org/api/n-api.html#environment-life-cycle-apis
//! [lifecycle]: https://raw.githubusercontent.com/neon-bindings/neon/main/doc/lifecycle.png
//! [workers]: https://nodejs.org/api/worker_threads.html
//! [threadId]: https://nodejs.org/api/worker_threads.html#workerthreadid

use std::any::Any;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};

use once_cell::sync::OnceCell;

use crate::context::Context;
use crate::lifecycle::LocalCell;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

fn next_id() -> usize {
    COUNTER.fetch_add(1, Ordering::SeqCst)
}

/// A JavaScript thread-local container that owns its contents, similar to
/// [`std::thread::LocalKey`](std::thread::LocalKey) but tied to a JavaScript thread rather
/// than a system thread.
///
/// ### Initialization and Destruction
///
/// Initialization is dynamically performed on the first call to one of the `init` methods
/// of `LocalKey`, and values that implement [`Drop`](std::ops::Drop) get destructed when
/// the JavaScript thread exits, i.e. when a worker thread terminates or the main thread
/// terminates on process exit.
#[derive(Default)]
pub struct LocalKey<T> {
    _type: PhantomData<T>,
    id: OnceCell<usize>,
}

impl<T> LocalKey<T> {
    /// Creates a new local value. This method is `const`, so it can be assigned to
    /// static variables.
    pub const fn new() -> Self {
        Self {
            _type: PhantomData,
            id: OnceCell::new(),
        }
    }

    fn id(&self) -> usize {
        *self.id.get_or_init(next_id)
    }
}

impl<T: Any + Send + 'static> LocalKey<T> {
    /// Gets the current value of the cell. Returns `None` if the cell has not
    /// yet been initialized.
    pub fn get<'cx, 'a, C>(&self, cx: &'a mut C) -> Option<&'cx T>
    where
        C: Context<'cx>,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: Option<&T> =
            LocalCell::get(cx, self.id()).map(|value| value.downcast_ref().unwrap());

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<Option<&'a T>, Option<&'cx T>>(r) }
    }

    /// Gets the current value of the cell, initializing it with the result of
    /// calling `f` if it has not yet been initialized.
    pub fn get_or_init<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> &'cx T
    where
        C: Context<'cx>,
        F: FnOnce() -> T,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = LocalCell::get_or_init(cx, self.id(), || Box::new(f()))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the cell, initializing it with the result of
    /// calling `f` if it has not yet been initialized. Returns `Err` if the
    /// callback triggers a JavaScript exception.
    ///
    /// # Panics
    ///
    /// During the execution of `f`, calling any methods on this `LocalKey` that
    /// attempt to initialize it will panic.
    pub fn get_or_try_init<'cx, 'a, C, E, F>(&self, cx: &'a mut C, f: F) -> Result<&'cx T, E>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> Result<T, E>,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = LocalCell::get_or_try_init(cx, self.id(), |cx| Ok(Box::new(f(cx)?)))?
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        Ok(unsafe { std::mem::transmute::<&'a T, &'cx T>(r) })
    }
}

impl<T: Any + Send + Default + 'static> LocalKey<T> {
    /// Gets the current value of the cell, initializing it with the default value
    /// if it has not yet been initialized.
    pub fn get_or_init_default<'cx, 'a, C>(&self, cx: &'a mut C) -> &'cx T
    where
        C: Context<'cx>,
    {
        self.get_or_init(cx, Default::default)
    }
}
<commit_msg>s/fail/panic/ in doc text<commit_after>//! Thread-local storage for JavaScript threads.
//!
//! At runtime, an instance of a Node.js addon can contain its own local storage,
//! which can then be shared and accessed as needed from Rust in a Neon module. This can
//! be useful for setting up long-lived state that needs to be shared between calls
//! of an addon's APIs.
//!
//! For example, an addon may wish to track the [thread ID][threadId] of each of its
//! instances:
//!
//! ```
//! # use neon::prelude::*;
//! # use neon::thread::LocalKey;
//! static THREAD_ID: LocalKey<u32> = LocalKey::new();
//!
//! pub fn thread_id<'cx, C: Context<'cx>>(cx: &mut C) -> NeonResult<u32> {
//!     THREAD_ID.get_or_try_init(cx, |cx| {
//!         let global = cx.global();
//!         let require: Handle<JsFunction> = global.get(cx, "require")?;
//!         let worker: Handle<JsObject> = require.call_with(cx)
//!             .arg(cx.string("node:worker_threads"))
//!             .apply(cx)?;
//!         let thread_id: Handle<JsNumber> = worker.get(cx, "threadId")?;
//!         Ok(thread_id.value(cx) as u32)
//!     }).cloned()
//! }
//! ```
//!
//! ### The Addon Lifecycle
//!
//! For some use cases, a single shared global constant stored in a `static` variable
//! might be sufficient:
//!
//! ```
//! static MY_CONSTANT: &'static str = "hello Neon";
//! ```
//!
//! This variable will be allocated when the addon is first loaded into the Node.js
//! process. This works fine for single-threaded applications, or global immutable
//! data.
//!
//! However, since the addition of [worker threads][workers] in Node v10,
//! modules can be instantiated multiple times in a single Node process. This means
//! that while the dynamically-loaded binary library (i.e., the Rust implementation of
//! the addon) is only loaded once in the running process, but its [`#[main]`](neon::main) function
//! is executed multiple times with distinct module objects, once per application thread:
//!
//! ![The Node.js addon lifecycle, described in detail below.][lifecycle]
//!
//! This means that any thread-local data needs to be initialized separately for each
//! instance of the addon. This module provides a simple container type, [`LocalKey`](LocalKey),
//! for allocating and initializing thread-local data. (Technically, this data is stored in the
//! addon's [module instance][environment], which is equivalent to being thread-local.)
//!
//! A common example is when an addon needs to maintain a reference to a JavaScript value. References cannot
//! be used across separate threads. The constructor for the datatype can be [rooted](crate::handle::Root) and
//! saved in thread-local storage:
//!
//! ```
//! # use neon::prelude::*;
//! # use neon::thread::LocalKey;
//! # fn initialize_my_datatype<'cx, C: Context<'cx>>(cx: &mut C) -> JsResult<'cx, JsFunction> { unimplemented!() }
//! static MY_CONSTRUCTOR: LocalKey<Root<JsFunction>> = LocalKey::new();
//!
//! pub fn my_constructor<'cx, C: Context<'cx>>(cx: &mut C) -> JsResult<'cx, JsFunction> {
//!     let constructor = MY_CONSTRUCTOR.get_or_try_init(cx, |cx| {
//!         let constructor: Handle<JsFunction> = initialize_my_datatype(cx)?;
//!         Ok(constructor.root(cx))
//!     })?;
//!     Ok(constructor.to_inner(cx))
//! }
//! ```
//!
//! Notice that if this code were implemented without a `LocalKey`, it would panic whenever
//! one thread stores an instance of the constructor and a different thread attempts to
//! access it with the call to [`to_inner()`](crate::handle::Root::to_inner).
//!
//! ### When to Use Thread-Local Storage
//!
//! Single-threaded applications don't generally need to worry about thread-local data.
//! There are two cases where Neon apps should consider storing static data in a
//! `LocalKey` storage cell:
//!
//! - **Multi-threaded applications:** If your Node application uses the `Worker`
//!   API, you'll want to store any static data that might get access from multiple
//!   threads in thread-local data.
//! - **Libraries:** If your addon is part of a library that could be used by multiple
//!   applications, you'll want to store static data in thread-local data in case the
//!   addon ends up instantiated by multiple threads in some future application.
//!
//! ### Why Not Use Standard TLS?
//!
//! Because the JavaScript engine may not tie JavaScript threads 1:1 to system threads,
//! it is recommended to use this module instead of the Rust standard thread-local storage
//! when tying data to a JavaScript thread.
//!
//! [environment]: https://nodejs.org/api/n-api.html#environment-life-cycle-apis
//! [lifecycle]: https://raw.githubusercontent.com/neon-bindings/neon/main/doc/lifecycle.png
//! [workers]: https://nodejs.org/api/worker_threads.html
//! [threadId]: https://nodejs.org/api/worker_threads.html#workerthreadid

use std::any::Any;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};

use once_cell::sync::OnceCell;

use crate::context::Context;
use crate::lifecycle::LocalCell;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

fn next_id() -> usize {
    COUNTER.fetch_add(1, Ordering::SeqCst)
}

/// A JavaScript thread-local container that owns its contents, similar to
/// [`std::thread::LocalKey`](std::thread::LocalKey) but tied to a JavaScript thread rather
/// than a system thread.
///
/// ### Initialization and Destruction
///
/// Initialization is dynamically performed on the first call to one of the `init` methods
/// of `LocalKey`, and values that implement [`Drop`](std::ops::Drop) get destructed when
/// the JavaScript thread exits, i.e. when a worker thread terminates or the main thread
/// terminates on process exit.
#[derive(Default)]
pub struct LocalKey<T> {
    _type: PhantomData<T>,
    id: OnceCell<usize>,
}

impl<T> LocalKey<T> {
    /// Creates a new local value. This method is `const`, so it can be assigned to
    /// static variables.
    pub const fn new() -> Self {
        Self {
            _type: PhantomData,
            id: OnceCell::new(),
        }
    }

    fn id(&self) -> usize {
        *self.id.get_or_init(next_id)
    }
}

impl<T: Any + Send + 'static> LocalKey<T> {
    /// Gets the current value of the cell. Returns `None` if the cell has not
    /// yet been initialized.
    pub fn get<'cx, 'a, C>(&self, cx: &'a mut C) -> Option<&'cx T>
    where
        C: Context<'cx>,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: Option<&T> =
            LocalCell::get(cx, self.id()).map(|value| value.downcast_ref().unwrap());

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<Option<&'a T>, Option<&'cx T>>(r) }
    }

    /// Gets the current value of the cell, initializing it with the result of
    /// calling `f` if it has not yet been initialized.
    pub fn get_or_init<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> &'cx T
    where
        C: Context<'cx>,
        F: FnOnce() -> T,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = LocalCell::get_or_init(cx, self.id(), || Box::new(f()))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the cell, initializing it with the result of
    /// calling `f` if it has not yet been initialized. Returns `Err` if the
    /// callback triggers a JavaScript exception.
    ///
    /// # Panics
    ///
    /// During the execution of `f`, calling any methods on this `LocalKey` that
    /// attempt to initialize it will panic.
    pub fn get_or_try_init<'cx, 'a, C, E, F>(&self, cx: &'a mut C, f: F) -> Result<&'cx T, E>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> Result<T, E>,
    {
        // Unwrap safety: The type bound LocalKey<T> and the fact that every LocalKey has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = LocalCell::get_or_try_init(cx, self.id(), |cx| Ok(Box::new(f(cx)?)))?
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        Ok(unsafe { std::mem::transmute::<&'a T, &'cx T>(r) })
    }
}

impl<T: Any + Send + Default + 'static> LocalKey<T> {
    /// Gets the current value of the cell, initializing it with the default value
    /// if it has not yet been initialized.
    pub fn get_or_init_default<'cx, 'a, C>(&self, cx: &'a mut C) -> &'cx T
    where
        C: Context<'cx>,
    {
        self.get_or_init(cx, Default::default)
    }
}
<|endoftext|>


<commit_before>//! JMESPath compliance tests.
//!
//! Test cases are generated using build.rs. This may eventually be exposed
//! as a library (leading to possibilities like a compliance test runner CLI).

extern crate serde_json;
extern crate jmespath;

use std::fmt;
use std::rc::Rc;

use serde_json::Value;

use jmespath::{Variable, RcVar, RuntimeError, Expression};

/// Avaliable benchmark types.
#[derive(Debug)]
pub enum BenchType {
    /// The benchmark must only parse an expression.
    Parse,
    /// The benchmark must parse and evaluate an expression.
    Full
}

/// Test case assertions.
pub enum Assertion {
    /// Ensures that the expression fails due to an invalid-arity error.
    InvalidArity,
    /// Ensures that the expression fails due to an invalid-type error.
    InvalidType,
    /// Ensures that the expression fails due to an invalid-value error.
    InvalidSlice,
    /// Ensures that the expression fails due to an unknown-function error.
    UnknownFunction,
    /// Ensures that an expression cannot be parsed due to a syntax error.
    SyntaxError,
    /// Ignores the result and marks the test as a benchmark
    Bench(BenchType),
    /// Ensures that the expression is parsed and returns an expected result.
    ValidResult(RcVar)
}

impl Assertion {
    /// Runs the assertion of a test case
    pub fn assert(&self,
                  suite: &str,
                  case: &TestCase,
                  given: RcVar) -> Result<(), String> {
        match self {
            &Assertion::InvalidArity => {
                match try!(self.try_parse(suite, case)).search(given.clone()) {
                    Err(RuntimeError::NotEnoughArguments{..}) => Ok(()),
                    Err(RuntimeError::TooManyArguments{..}) => Ok(()),
                    Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                    Ok(r) => Err(self.err_message(suite, case, r.to_string().unwrap())),
                }
            },
            &Assertion::InvalidType => {
                match try!(self.try_parse(suite, case)).search(given.clone()) {
                    Err(RuntimeError::InvalidType{..}) => Ok(()),
                    Err(RuntimeError::InvalidReturnType{..}) => Ok(()),
                    Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                    Ok(r) => Err(self.err_message(suite, case, r.to_string().unwrap())),
                }
            },
            &Assertion::InvalidSlice => {
                match try!(self.try_parse(suite, case)).search(given.clone()) {
                    Err(RuntimeError::InvalidSlice) => Ok(()),
                    Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                    Ok(r) => Err(self.err_message(suite, case, r.to_string().unwrap())),
                }
            },
            &Assertion::UnknownFunction => {
                match try!(self.try_parse(suite, case)).search(given) {
                    Err(RuntimeError::UnknownFunction{..}) => Ok(()),
                    Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                    Ok(r) => Err(self.err_message(suite, case, r.to_string().unwrap())),
                }
            },
            &Assertion::SyntaxError => {
                match Expression::new(&case.expression) {
                    Err(_) => Ok(()),
                    Ok(expr) => Err(self.err_message(suite, case, format!("Parsed {:?}", expr)))
                }
            },
            &Assertion::Bench(_) => Ok(()),
            &Assertion::ValidResult(ref expected_result) => {
                match try!(self.try_parse(suite, case)).search(given) {
                    Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                    Ok(r) => {
                        match r.as_string() {
                            Some(s) if s != expected_result.as_string().unwrap() => {
                                Err(self.err_message(suite, case, r.to_string().unwrap()))
                            },
                            Some(_) if r != expected_result.clone() => {
                                Err(self.err_message(suite, case, r.to_string().unwrap()))
                            },
                            _ => Ok(())
                        }
                    }
                }
            }
        }
    }

    /// Attempts to parse an expression for a case, returning the expression or an error string.
    fn try_parse<'a>(&self, suite: &str, case: &'a TestCase) -> Result<Expression<'a>, String> {
        match Expression::new(&case.expression) {
            Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
            Ok(expr) => Ok(expr)
        }
    }

    /// Formats an error message for a test case failure.
    fn err_message(&self, suite: &str, case: &TestCase, message: String) -> String {
        format!("Test suite: {}\nExpression: {}\nAssertion: {}\nResult: {}\n==============",
                 suite, case.expression, self, message).to_string()
    }

    /// Try to create a benchmark assertion from a JSON value.
    fn bench_from_json(bench_type: &Value) -> Result<Self, TestCaseError> {
        bench_type.as_string()
            .ok_or(TestCaseError::BenchIsNotString)
            .and_then(|b| {
                match b {
                    "parse" => Ok(Assertion::Bench(BenchType::Parse)),
                    "full" => Ok(Assertion::Bench(BenchType::Full)),
                    s @ _ => Err(TestCaseError::UnknownBenchType(s.to_string()))
                }
            })
    }

    /// Try to create an error assertion from a JSON value.
    fn error_from_json(error_type: &Value) -> Result<Self, TestCaseError> {
        error_type.as_string()
            .ok_or(TestCaseError::ErrorIsNotString)
            .and_then(|b| {
                match b {
                    "syntax" => Ok(Assertion::SyntaxError),
                    "invalid-type" => Ok(Assertion::InvalidType),
                    "invalid-value" => Ok(Assertion::InvalidSlice),
                    "invalid-arity" => Ok(Assertion::InvalidArity),
                    "unknown-function" => Ok(Assertion::UnknownFunction),
                    e @ _ => Err(TestCaseError::UnknownErrorType(e.to_string())),
                }
            })
    }
}

impl fmt::Display for Assertion {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::Assertion::*;
        match self {
            &InvalidArity => write!(fmt, "expects error(invalid-arity)"),
            &InvalidType => write!(fmt, "expects error(invalid-type)"),
            &InvalidSlice => write!(fmt, "expects error(invalid-value)"),
            &UnknownFunction => write!(fmt, "expects error(unknown-function)"),
            &SyntaxError => write!(fmt, "expects error(syntax)"),
            &Bench(ref b) => write!(fmt, "expects benchmark({:?})", b),
            &ValidResult(ref r) => write!(fmt, "expects result({:?})", r),
        }
    }
}

/// The test suite holds a collection of test cases and has a given value.
#[allow(dead_code)]
pub struct TestSuite<'a> {
    /// Filename of the test suite
    filename: &'a str,
    /// Given data of the test suite
    given: RcVar,
    /// Collection of test cases to perform
    cases: Vec<TestCase>,
}

impl<'a> TestSuite<'a> {
    /// Creates a test suite from JSON string.
    pub fn from_str(filename: &'a str, suite: &str) -> Result<TestSuite<'a>, String> {
        serde_json::from_str::<Value>(suite)
            .map_err(|e| e.to_string())
            .and_then(|j| TestSuite::from_json(filename, &j))
    }

    /// Creates a test suite from parsed JSON data.
    fn from_json(filename: &'a str, suite: &Value) -> Result<TestSuite<'a>, String> {
        let suite = try!(suite.as_object().ok_or("test suite is not an object"));
        let test_case = try!(suite.get("cases").ok_or("No cases value".to_string()));
        let case_array = try!(test_case.as_array().ok_or("cases is not an array".to_string()));
        let mut cases = vec![];
        for case in case_array {
            cases.push(try!(TestCase::from_json(case).map_err(|e| e.to_string())));
        }

        Ok(TestSuite {
            filename: filename,
            given: Rc::new(Variable::from_json(try!(
                suite.get("given").ok_or("No given value".to_string())))),
            cases: cases
        })
    }
}

/// Errors that can occur when creating a TestCase
pub enum TestCaseError {
    InvalidJSON(String),
    NoCaseType,
    NoResult,
    ResultCannotToString,
    NoExpression,
    ExpressionIsNotString,
    ErrorIsNotString,
    UnknownErrorType(String),
    UnknownBenchType(String),
    BenchIsNotString,
}

impl fmt::Display for TestCaseError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::TestCaseError::*;
        match self {
            &InvalidJSON(ref msg) => write!(fmt, "invalid test case JSON: {}", msg),
            &NoCaseType => write!(fmt, "case has no result, error, or bench"),
            &NoResult => write!(fmt, "test case has no result key"),
            &ResultCannotToString => write!(fmt, "result could not be cast to string"),
            &NoExpression => write!(fmt, "test case has no expression key"),
            &ExpressionIsNotString => write!(fmt, "test case expression is not a string"),
            &ErrorIsNotString => write!(fmt, "test case error value is not a string"),
            &UnknownErrorType(ref t) => write!(fmt, "unknown error type: {}", t),
            &BenchIsNotString => write!(fmt, "bench value is not a string"),
            &UnknownBenchType(ref bench) => {
                write!(fmt, "unknown bench value: {}, expected one of of parse|full", bench)
            },
        }
    }
}

impl fmt::Debug for TestCaseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

/// Represents a test case that contains an expression and assertion.
pub struct TestCase {
    /// The expression being evaluated.
    pub expression: String,
    /// The assertion to perform for the test case.
    pub assertion: Assertion,
}

impl TestCase {
    /// Creates a test case from a JSON encoded string.
    pub fn from_str(case: &str) -> Result<TestCase, TestCaseError> {
        serde_json::from_str::<Value>(case)
            .map_err(|e| TestCaseError::InvalidJSON(e.to_string()))
            .and_then(|json| TestCase::from_json(&json))
    }

    /// Creates a test case from parsed JSON data.
    fn from_json(case: &Value) -> Result<TestCase, TestCaseError> {
        use TestCaseError::*;
        let case = try!(case.as_object().ok_or(InvalidJSON("not an object".to_string())));
        Ok(TestCase {
            expression: try!(
                case.get("expression")
                    .ok_or(NoExpression)
                    .and_then(|expression| expression.as_string()
                        .ok_or(ExpressionIsNotString)
                        .map(|expression_str| expression_str.to_string()))),
            assertion: match case.get("error") {
                Some(err) => try!(Assertion::error_from_json(err)),
                None if case.contains_key("result") => {
                    let value = Rc::new(Variable::from_json(case.get("result").unwrap()));
                    Assertion::ValidResult(value)
                },
                None if case.contains_key("bench") => {
                    try!(Assertion::bench_from_json(case.get("bench").unwrap()))
                },
                _ => return Err(NoCaseType)
            }
        })
    }

    /// Perform the test case assertion against a given value.
    pub fn assert(&self, suite_filename: &str, given: RcVar) -> Result<(), String> {
        self.assertion.assert(suite_filename, self, given)
    }
}

include!(concat!(env!("OUT_DIR"), "/compliance_tests.rs"));
<commit_msg>Giving test case error types an enum<commit_after>//! JMESPath compliance tests.
//!
//! Test cases are generated using build.rs. This may eventually be exposed
//! as a library (leading to possibilities like a compliance test runner CLI).

extern crate serde_json;
extern crate jmespath;

use std::fmt;
use std::rc::Rc;

use serde_json::Value;

use jmespath::{Variable, RcVar, RuntimeError, Expression};

/// Avaliable benchmark types.
pub enum BenchType {
    /// The benchmark must only parse an expression.
    Parse,
    /// The benchmark must parse and evaluate an expression.
    Full
}

impl BenchType {
    /// Try to create a benchmark assertion from a JSON value.
    fn from_json(bench_type: &Value) -> Result<Self, TestCaseError> {
        bench_type.as_string()
            .ok_or(TestCaseError::BenchIsNotString)
            .and_then(|b| {
                match b {
                    "parse" => Ok(BenchType::Parse),
                    "full" => Ok(BenchType::Full),
                    s @ _ => Err(TestCaseError::UnknownBenchType(s.to_string()))
                }
            })
    }
}

impl fmt::Display for BenchType {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &BenchType::Parse => write!(fmt, "parse"),
            &BenchType::Full => write!(fmt, "full"),
        }
    }
}

/// Avaliable error types.
pub enum ErrorType {
    /// Ensures that the expression fails due to an invalid-arity error.
    InvalidArity,
    /// Ensures that the expression fails due to an invalid-type error.
    InvalidType,
    /// Ensures that the expression fails due to an invalid-value error.
    InvalidSlice,
    /// Ensures that the expression fails due to an unknown-function error.
    UnknownFunction,
    /// Ensures that an expression cannot be parsed due to a syntax error.
    SyntaxError,
}

impl ErrorType {
    /// Try to create an error assertion from a JSON value.
    fn from_json(error_type: &Value) -> Result<Self, TestCaseError> {
        error_type.as_string()
            .ok_or(TestCaseError::ErrorIsNotString)
            .and_then(|b| {
                match b {
                    "syntax" => Ok(ErrorType::SyntaxError),
                    "invalid-type" => Ok(ErrorType::InvalidType),
                    "invalid-value" => Ok(ErrorType::InvalidSlice),
                    "invalid-arity" => Ok(ErrorType::InvalidArity),
                    "unknown-function" => Ok(ErrorType::UnknownFunction),
                    e @ _ => Err(TestCaseError::UnknownErrorType(e.to_string())),
                }
            })
    }
}

impl fmt::Display for ErrorType {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::ErrorType::*;
        match self {
            &InvalidArity => write!(fmt, "invalid-arity"),
            &InvalidType => write!(fmt, "invalid-type"),
            &InvalidSlice => write!(fmt, "invalid-value"),
            &UnknownFunction => write!(fmt, "unknown-function"),
            &SyntaxError => write!(fmt, "syntax"),
        }
    }
}

/// Test case assertions.
pub enum Assertion {
    /// Ensures that a test fails with a particular error type.
    Error(ErrorType),
    /// Ignores the result and marks the test as a benchmark
    Bench(BenchType),
    /// Ensures that the expression is parsed and returns an expected result.
    ValidResult(RcVar)
}

impl Assertion {
    /// Runs the assertion of a test case
    pub fn assert(&self,
                  suite: &str,
                  case: &TestCase,
                  given: RcVar) -> Result<(), String> {
        match self {
            &Assertion::Bench(_) => Ok(()),
            &Assertion::ValidResult(ref expected_result) => {
                match try!(self.try_parse(suite, case)).search(given) {
                    Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                    Ok(r) => {
                        match r.as_string() {
                            Some(s) if s != expected_result.as_string().unwrap() => {
                                Err(self.err_message(suite, case, r.to_string().unwrap()))
                            },
                            Some(_) if r != expected_result.clone() => {
                                Err(self.err_message(suite, case, r.to_string().unwrap()))
                            },
                            _ => Ok(())
                        }
                    }
                }
            },
            &Assertion::Error(ref error_type) => {
                match error_type {
                    &ErrorType::InvalidArity => {
                        match try!(self.try_parse(suite, case)).search(given.clone()) {
                            Err(RuntimeError::NotEnoughArguments{..}) => Ok(()),
                            Err(RuntimeError::TooManyArguments{..}) => Ok(()),
                            Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                            Ok(r) => Err(self.err_message(suite, case, r.to_string().unwrap())),
                        }
                    },
                    &ErrorType::InvalidType => {
                        match try!(self.try_parse(suite, case)).search(given.clone()) {
                            Err(RuntimeError::InvalidType{..}) => Ok(()),
                            Err(RuntimeError::InvalidReturnType{..}) => Ok(()),
                            Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                            Ok(r) => Err(self.err_message(suite, case, r.to_string().unwrap())),
                        }
                    },
                    &ErrorType::InvalidSlice => {
                        match try!(self.try_parse(suite, case)).search(given.clone()) {
                            Err(RuntimeError::InvalidSlice) => Ok(()),
                            Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                            Ok(r) => Err(self.err_message(suite, case, r.to_string().unwrap())),
                        }
                    },
                    &ErrorType::UnknownFunction => {
                        match try!(self.try_parse(suite, case)).search(given) {
                            Err(RuntimeError::UnknownFunction{..}) => Ok(()),
                            Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
                            Ok(r) => Err(self.err_message(suite, case, r.to_string().unwrap())),
                        }
                    },
                    &ErrorType::SyntaxError => {
                        match Expression::new(&case.expression) {
                            Err(_) => Ok(()),
                            Ok(expr) => {
                                Err(self.err_message(suite, case, format!("Parsed {:?}", expr)))
                            }
                        }
                    },
                }
            },
        }
    }

    /// Attempts to parse an expression for a case, returning the expression or an error string.
    fn try_parse<'a>(&self, suite: &str, case: &'a TestCase) -> Result<Expression<'a>, String> {
        match Expression::new(&case.expression) {
            Err(e) => Err(self.err_message(suite, case, format!("{}", e))),
            Ok(expr) => Ok(expr)
        }
    }

    /// Formats an error message for a test case failure.
    fn err_message(&self, suite: &str, case: &TestCase, message: String) -> String {
        format!("Test suite: {}\nExpression: {}\nAssertion: {}\nResult: {}\n==============",
                 suite, case.expression, self, message).to_string()
    }
}

impl fmt::Display for Assertion {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Assertion::Error(ref e) => write!(fmt, "expects error({})", e),
            &Assertion::Bench(ref b) => write!(fmt, "expects bench({})", b),
            &Assertion::ValidResult(ref r) => write!(fmt, "expects result({:?})", r),
        }
    }
}

/// The test suite holds a collection of test cases and has a given value.
#[allow(dead_code)]
pub struct TestSuite<'a> {
    /// Filename of the test suite
    filename: &'a str,
    /// Given data of the test suite
    given: RcVar,
    /// Collection of test cases to perform
    cases: Vec<TestCase>,
}

impl<'a> TestSuite<'a> {
    /// Creates a test suite from JSON string.
    pub fn from_str(filename: &'a str, suite: &str) -> Result<TestSuite<'a>, String> {
        serde_json::from_str::<Value>(suite)
            .map_err(|e| e.to_string())
            .and_then(|j| TestSuite::from_json(filename, &j))
    }

    /// Creates a test suite from parsed JSON data.
    fn from_json(filename: &'a str, suite: &Value) -> Result<TestSuite<'a>, String> {
        let suite = try!(suite.as_object().ok_or("test suite is not an object"));
        let test_case = try!(suite.get("cases").ok_or("No cases value".to_string()));
        let case_array = try!(test_case.as_array().ok_or("cases is not an array".to_string()));
        let mut cases = vec![];
        for case in case_array {
            cases.push(try!(TestCase::from_json(case).map_err(|e| e.to_string())));
        }

        Ok(TestSuite {
            filename: filename,
            given: Rc::new(Variable::from_json(try!(
                suite.get("given").ok_or("No given value".to_string())))),
            cases: cases
        })
    }
}

/// Errors that can occur when creating a TestCase
pub enum TestCaseError {
    InvalidJSON(String),
    NoCaseType,
    NoResult,
    ResultCannotToString,
    NoExpression,
    ExpressionIsNotString,
    ErrorIsNotString,
    UnknownErrorType(String),
    UnknownBenchType(String),
    BenchIsNotString,
}

impl fmt::Display for TestCaseError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::TestCaseError::*;
        match self {
            &InvalidJSON(ref msg) => write!(fmt, "invalid test case JSON: {}", msg),
            &NoCaseType => write!(fmt, "case has no result, error, or bench"),
            &NoResult => write!(fmt, "test case has no result key"),
            &ResultCannotToString => write!(fmt, "result could not be cast to string"),
            &NoExpression => write!(fmt, "test case has no expression key"),
            &ExpressionIsNotString => write!(fmt, "test case expression is not a string"),
            &ErrorIsNotString => write!(fmt, "test case error value is not a string"),
            &UnknownErrorType(ref t) => write!(fmt, "unknown error type: {}", t),
            &BenchIsNotString => write!(fmt, "bench value is not a string"),
            &UnknownBenchType(ref bench) => {
                write!(fmt, "unknown bench value: {}, expected one of of parse|full", bench)
            },
        }
    }
}

impl fmt::Debug for TestCaseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

/// Represents a test case that contains an expression and assertion.
pub struct TestCase {
    /// The expression being evaluated.
    pub expression: String,
    /// The assertion to perform for the test case.
    pub assertion: Assertion,
}

impl TestCase {
    /// Creates a test case from a JSON encoded string.
    pub fn from_str(case: &str) -> Result<TestCase, TestCaseError> {
        serde_json::from_str::<Value>(case)
            .map_err(|e| TestCaseError::InvalidJSON(e.to_string()))
            .and_then(|json| TestCase::from_json(&json))
    }

    /// Creates a test case from parsed JSON data.
    fn from_json(case: &Value) -> Result<TestCase, TestCaseError> {
        use TestCaseError::*;
        let case = try!(case.as_object().ok_or(InvalidJSON("not an object".to_string())));
        Ok(TestCase {
            expression: try!(
                case.get("expression")
                    .ok_or(NoExpression)
                    .and_then(|expression| expression.as_string()
                        .ok_or(ExpressionIsNotString)
                        .map(|expression_str| expression_str.to_string()))),
            assertion: match case.get("error") {
                Some(err) => Assertion::Error(try!(ErrorType::from_json(err))),
                None if case.contains_key("result") => {
                    let value = Rc::new(Variable::from_json(case.get("result").unwrap()));
                    Assertion::ValidResult(value)
                },
                None if case.contains_key("bench") => {
                    Assertion::Bench(try!(BenchType::from_json(case.get("bench").unwrap())))
                },
                _ => return Err(NoCaseType)
            }
        })
    }

    /// Perform the test case assertion against a given value.
    pub fn assert(&self, suite_filename: &str, given: RcVar) -> Result<(), String> {
        self.assertion.assert(suite_filename, self, given)
    }
}

include!(concat!(env!("OUT_DIR"), "/compliance_tests.rs"));
<|endoftext|>


<commit_before>use cucumber::{Context, Cucumber};
use mimir2::adapters::secondary::elasticsearch::remote::connection_test_pool;

mod error;
mod state;
mod steps;
mod utils;

#[tokio::main]
async fn main() {
    let pool = connection_test_pool().await.unwrap();

    Cucumber::<state::State>::new()
        // Specifies where our feature files exist
        .features(&["./features/admin", "./features/addresses"])
        // Adds the implementation of our steps to the runner
        .steps(steps::download::steps())
        .steps(steps::admin::steps())
        .steps(steps::address::steps())
        .steps(steps::search::steps())
        // Add some global context for all the tests, like databases.
        .context(Context::new().add(pool))
        // Parses the command line arguments if passed
        .cli()
        // Runs the Cucumber tests and then exists
        .run_and_exit()
        .await
}
<commit_msg>cleanup ES before end to end tests<commit_after>use cucumber::{Context, Cucumber};
use mimir2::adapters::secondary::elasticsearch::remote::connection_test_pool;
use mimir2::utils::docker;

mod error;
mod state;
mod steps;
mod utils;

#[tokio::main]
async fn main() {
    let _guard = docker::initialize()
        .await
        .expect("elasticsearch docker initialization");

    let pool = connection_test_pool().await.unwrap();

    Cucumber::<state::State>::new()
        // Specifies where our feature files exist
        .features(&["./features/admin", "./features/addresses"])
        // Adds the implementation of our steps to the runner
        .steps(steps::download::steps())
        .steps(steps::admin::steps())
        .steps(steps::address::steps())
        .steps(steps::search::steps())
        // Add some global context for all the tests, like databases.
        .context(Context::new().add(pool))
        // Parses the command line arguments if passed
        .cli()
        // Runs the Cucumber tests and then exists
        .run_and_exit()
        .await
}
<|endoftext|>


<commit_before>//! Database operations

use postgres::{Connection, SslMode};
use postgres::error::ConnectError;

const DB_CONNECTION_STR: &'static str = "postgresql://cratesfyi@localhost";

/// Connects to database
pub fn connect_db() -> Result<Connection, ConnectError> {
    Connection::connect(DB_CONNECTION_STR, SslMode::None)
}

/// Creates database tables
pub fn create_tables(conn: &Connection) {
    let tables = [
        "CREATE TABLE crates ( \
            id SERIAL, \
            name text UNIQUE NOT NULL, \
            latest_version_id INT DEFAULT 0, \
            github_stars INT DEFAULT 0, \
            badges JSON, \
            issues JSON, \
            downloads_total INT DEFAULT 0 \
        )",
        "CREATE TABLE releases ( \
            id SERIAL, \
            crate_id INT NOT NULL, \
            version TEXT, \
            release_time TIMESTAMP, \
            dependencies JSON, \
            yanked BOOL DEFAULT FALSE, \
            build_status INT DEFAULT 0, \
            rustdoc_status INT DEFAULT 0, \
            test_status INT DEFAULT 0, \
            license TEXT, \
            repository_url TEXT, \
            homepage_url TEXT, \
            description TEXT, \
            description_long TEXT, \
            readme TEXT, \
            authors JSON, \
            keywords JSON, \
            downloads INT DEFAULT 0 \
        )",
        "CREATE TABLE authors ( \
            id SERIAL, \
            name TEXT NOT NULL, \
            email TEXT, \
            slug TEXT UNIQUE NOT NULL, \
            github_url TEXT, \
            github_profile_picture_url TEXT \
        )",
        "CREATE TABLE author_rels ( \
            cid INT, \
            aid INT, \
            UNIQUE(cid, aid) \
        )",
        "CREATE TABLE keywords ( \
            id SERIAL, \
            name TEXT, \
            slug TEXT NOT NULL UNIQUE \
        )",
        "CREATE TABLE keyword_rels ( \
            cid INT, \
            kid INT, \
            UNIQUE(cid, kid) \
        )"
    ];

    for table in tables.into_iter() {
        if let Err(e) = conn.execute(table, &[]) {
            println!("{}", e);
        }
    }
}

#[test]
#[ignore]
fn test_connect_db() {
    let conn = connect_db();
    assert!(conn.is_ok());
}
<commit_msg>Make crate_id and version UNIQUE<commit_after>//! Database operations

use postgres::{Connection, SslMode};
use postgres::error::ConnectError;

const DB_CONNECTION_STR: &'static str = "postgresql://cratesfyi@localhost";

/// Connects to database
pub fn connect_db() -> Result<Connection, ConnectError> {
    Connection::connect(DB_CONNECTION_STR, SslMode::None)
}

/// Creates database tables
pub fn create_tables(conn: &Connection) {
    let tables = [
        "CREATE TABLE crates ( \
            id SERIAL, \
            name text UNIQUE NOT NULL, \
            latest_version_id INT DEFAULT 0, \
            github_stars INT DEFAULT 0, \
            badges JSON, \
            issues JSON, \
            downloads_total INT DEFAULT 0 \
        )",
        "CREATE TABLE releases ( \
            id SERIAL, \
            crate_id INT NOT NULL, \
            version TEXT, \
            release_time TIMESTAMP, \
            dependencies JSON, \
            yanked BOOL DEFAULT FALSE, \
            build_status INT DEFAULT 0, \
            rustdoc_status INT DEFAULT 0, \
            test_status INT DEFAULT 0, \
            license TEXT, \
            repository_url TEXT, \
            homepage_url TEXT, \
            description TEXT, \
            description_long TEXT, \
            readme TEXT, \
            authors JSON, \
            keywords JSON, \
            downloads INT DEFAULT 0, \
            UNIQUE (crate_id, version) \
        )",
        "CREATE TABLE authors ( \
            id SERIAL, \
            name TEXT NOT NULL, \
            email TEXT, \
            slug TEXT UNIQUE NOT NULL, \
            github_url TEXT, \
            github_profile_picture_url TEXT \
        )",
        "CREATE TABLE author_rels ( \
            cid INT, \
            aid INT, \
            UNIQUE(cid, aid) \
        )",
        "CREATE TABLE keywords ( \
            id SERIAL, \
            name TEXT, \
            slug TEXT NOT NULL UNIQUE \
        )",
        "CREATE TABLE keyword_rels ( \
            cid INT, \
            kid INT, \
            UNIQUE(cid, kid) \
        )"
    ];

    for table in tables.into_iter() {
        if let Err(e) = conn.execute(table, &[]) {
            println!("{}", e);
        }
    }
}

#[test]
#[ignore]
fn test_connect_db() {
    let conn = connect_db();
    assert!(conn.is_ok());
}
<|endoftext|>


<commit_before>use crate::AsArray2D;
use russell_lab::Matrix;
use std::collections::HashMap;

pub enum BlockKind {
    Qua4,
    Qua8,
    Hex8,
    Hex20,
}

pub enum Constraint {}

pub struct ConstraintData {
    kind: Constraint,
}

/// Defines a polygon on polyhedron that can be split into smaller shapes
///
/// # Block shape
///
/// ## 2D: Local indices of points and edges
///
/// ```text
///             Points (4 or 8)                        Edges (4)
///   y
///   |        3      6      2                             2
///   +--x      @-----@-----@                        +-----------+
///             |           |                        |           |
///             |           |                        |           |
///           7 @           @ 5                     3|           |1
///             |           |                        |           |
///             |           |                        |           |
///             @-----@-----@                        +-----------+
///            0      4      1                             0
/// ```
///
/// ## 3D: Local indices of points, edges, and faces
///
/// ```text
///                   Points (8 or 20)                   Faces (6)
///    z
///    |           4        15        7
///   ,+--y         @-------@--------@                 +----------------+
/// x'            ,'|              ,'|               ,'|              ,'|
///          12 @'  |         14 ,'  |             ,'  |  ___       ,'  |
///           ,'    |16        ,@    |19         ,'    |,'5,'  [0],'    |
///     5   ,'      @      6 ,'      @         ,'      |~~~     ,'      |
///       @'=======@=======@'        |       +'===============+'  ,'|   |
///       |      13 |      |         |       |   ,'|   |      |   |3|   |
///       |         |      |  11     |       |   |2|   |      |   |,'   |
///    17 |       0 @- - - | @- - - -@       |   |,'   +- - - | +- - - -+
///       @       ,'       @       ,' 3      |       ,'       |       ,'
///       |   8 @'      18 |     ,'          |     ,' [1]  ___|     ,'
///       |   ,'           |   ,@ 10         |   ,'      ,'4,'|   ,'
///       | ,'             | ,'              | ,'        ~~~  | ,'
///       @-------@--------@'                +----------------+'
///     1         9         2
///
///
///                  Edges (12)
///
///                         7
///                 +----------------+
///               ,'|              ,'|
///           4 ,'  |8          6,'  |
///           ,'    |          ,'    |
///         ,'      |   5    ,'      |11
///       +'===============+'        |
///       |         |      |         |
///       |         |      |  3      |
///       |         .- - - | -  - - -+
///      9|       ,'       |       ,'
///       |    0,'         |10   ,'
///       |   ,'           |   ,' 2
///       | ,'             | ,'
///       +----------------+'
///               1
///
pub struct Block {
    group: usize,             // group of all elements in this block
    ndim: usize,              // space dimension
    npoint: usize,            // number of points (4, 8, or 20)
    nedge: usize,             // number of edges (4 or 12)
    nface: usize,             // number of faces (4 or 6)
    coords: Matrix,           // coordinates of points (npoint, ndim)
    point_groups: Vec<usize>, // point groups (npoint)
    edge_groups: Vec<usize>,  // edge groups (nedge)
    face_groups: Vec<usize>,  // face groups (nface)
    num_div: Vec<usize>,      // number of divisions along each dim (ndim)
    weights: Vec<Vec<f64>>,   // weights along each dimension (ndim, nweight)
    sum_weights: Vec<f64>,    // sum of weights along each dimension (ndim)

    // maps side to constraint (num_sides)
    constraints: HashMap<Constraint, ConstraintData>,
}

impl Block {
    pub fn new(group: usize, kind: BlockKind) -> Self {
        let (ndim, npoint, nedge, nface) = match kind {
            BlockKind::Qua4 => (2, 4, 4, 0),
            BlockKind::Qua8 => (2, 8, 4, 0),
            BlockKind::Hex8 => (3, 8, 12, 6),
            BlockKind::Hex20 => (3, 20, 12, 6),
        };
        Block {
            group,
            ndim,
            npoint,
            nedge,
            nface,
            coords: Matrix::new(npoint, ndim),
            point_groups: vec![0; npoint],
            edge_groups: vec![0; nedge],
            face_groups: vec![0; nface],
            num_div: vec![0; ndim],
            weights: vec![Vec::new(); ndim],
            sum_weights: vec![0.0; ndim],
            constraints: HashMap::new(),
        }
    }

    pub fn set_point_2d(&mut self, m: usize, group: usize, x: f64, y: f64) -> &mut Self {
        assert_eq!(self.ndim, 2);
        assert!(m < self.npoint);
        self.point_groups[m] = group;
        self.coords[m][0] = x;
        self.coords[m][1] = y;
        self
    }

    pub fn set_point_3d(&mut self, m: usize, group: usize, x: f64, y: f64, z: f64) -> &mut Self {
        assert_eq!(self.ndim, 3);
        assert!(m < self.npoint);
        self.point_groups[m] = group;
        self.coords[m][0] = x;
        self.coords[m][1] = y;
        self.coords[m][2] = z;
        self
    }

    pub fn set_coords<'a, T, U>(&mut self, coords: &'a T) -> &mut Self
    where
        T: AsArray2D<'a, U>,
        U: 'a + Into<f64>,
    {
        let (nrow, ncol) = coords.size();
        assert_eq!(nrow, self.npoint);
        assert_eq!(ncol, self.ndim);
        for i in 0..nrow {
            for j in 0..ncol {
                self.coords[i][j] = coords.at(i, j).into();
            }
        }
        self
    }
}

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

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

    #[test]
    fn new_works() {
        let block = Block::new(1, BlockKind::Qua4);
        assert_eq!(block.group, 1);
        assert_eq!(block.ndim, 2);
        assert_eq!(block.npoint, 4);
        assert_eq!(block.nedge, 4);
        assert_eq!(block.nface, 0);
    }

    #[test]
    fn set_point_2d_works() {
        let mut block = Block::new(1, BlockKind::Qua4);
        block
            .set_point_2d(0, 1, 0.0, 0.0)
            .set_point_2d(1, 2, 2.0, 0.0)
            .set_point_2d(2, 3, 2.0, 2.0)
            .set_point_2d(3, 4, 0.0, 2.0);
        assert_eq!(
            format!("{}", block.coords),
            "┌     ┐\n\
             │ 0 0 │\n\
             │ 2 0 │\n\
             │ 2 2 │\n\
             │ 0 2 │\n\
             └     ┘"
        );
    }

    #[test]
    fn set_point_3d_works() {
        let mut block = Block::new(1, BlockKind::Hex8);
        block
            .set_point_3d(0, 1, 0.0, 0.0, 0.0)
            .set_point_3d(1, 2, 2.0, 0.0, 0.0)
            .set_point_3d(2, 3, 2.0, 2.0, 0.0)
            .set_point_3d(3, 4, 0.0, 2.0, 0.0)
            .set_point_3d(4, 1, 0.0, 0.0, 2.0)
            .set_point_3d(5, 2, 2.0, 0.0, 2.0)
            .set_point_3d(6, 3, 2.0, 2.0, 2.0)
            .set_point_3d(7, 4, 0.0, 2.0, 2.0);
        assert_eq!(
            format!("{}", block.coords),
            "┌       ┐\n\
             │ 0 0 0 │\n\
             │ 2 0 0 │\n\
             │ 2 2 0 │\n\
             │ 0 2 0 │\n\
             │ 0 0 2 │\n\
             │ 2 0 2 │\n\
             │ 2 2 2 │\n\
             │ 0 2 2 │\n\
             └       ┘"
        );
    }

    #[test]
    fn set_coords_works() {
        let mut qua4 = Block::new(1, BlockKind::Qua4);
        #[rustfmt::skip]
        qua4.set_coords(&[
            [0.0, 0.0],
            [2.0, 0.0],
            [2.0, 2.0],
            [0.0, 2.0],
        ]);
        assert_eq!(
            format!("{}", qua4.coords),
            "┌     ┐\n\
             │ 0 0 │\n\
             │ 2 0 │\n\
             │ 2 2 │\n\
             │ 0 2 │\n\
             └     ┘"
        );

        let mut hex8 = Block::new(1, BlockKind::Hex8);
        #[rustfmt::skip]
        hex8.set_coords(&[
            [0.0, 0.0, 0.0],
            [2.0, 0.0, 0.0],
            [2.0, 2.0, 0.0],
            [0.0, 2.0, 0.0],
            [0.0, 0.0, 2.0],
            [2.0, 0.0, 2.0],
            [2.0, 2.0, 2.0],
            [0.0, 2.0, 2.0],
        ]);
        assert_eq!(
            format!("{}", hex8.coords),
            "┌       ┐\n\
             │ 0 0 0 │\n\
             │ 2 0 0 │\n\
             │ 2 2 0 │\n\
             │ 0 2 0 │\n\
             │ 0 0 2 │\n\
             │ 2 0 2 │\n\
             │ 2 2 2 │\n\
             │ 0 2 2 │\n\
             └       ┘"
        );
    }
}
<commit_msg>Add method<commit_after>use crate::AsArray2D;
use russell_lab::Matrix;
use std::collections::HashMap;

pub enum BlockKind {
    Qua4,
    Qua8,
    Hex8,
    Hex20,
}

pub enum Constraint {}

pub struct ConstraintData {
    kind: Constraint,
}

/// Defines a polygon on polyhedron that can be split into smaller shapes
///
/// # Block shape
///
/// ## 2D: Local indices of points and edges
///
/// ```text
///             Points (4 or 8)                        Edges (4)
///   y
///   |        3      6      2                             2
///   +--x      @-----@-----@                        +-----------+
///             |           |                        |           |
///             |           |                        |           |
///           7 @           @ 5                     3|           |1
///             |           |                        |           |
///             |           |                        |           |
///             @-----@-----@                        +-----------+
///            0      4      1                             0
/// ```
///
/// ## 3D: Local indices of points, edges, and faces
///
/// ```text
///                   Points (8 or 20)                   Faces (6)
///    z
///    |           4        15        7
///   ,+--y         @-------@--------@                 +----------------+
/// x'            ,'|              ,'|               ,'|              ,'|
///          12 @'  |         14 ,'  |             ,'  |  ___       ,'  |
///           ,'    |16        ,@    |19         ,'    |,'5,'  [0],'    |
///     5   ,'      @      6 ,'      @         ,'      |~~~     ,'      |
///       @'=======@=======@'        |       +'===============+'  ,'|   |
///       |      13 |      |         |       |   ,'|   |      |   |3|   |
///       |         |      |  11     |       |   |2|   |      |   |,'   |
///    17 |       0 @- - - | @- - - -@       |   |,'   +- - - | +- - - -+
///       @       ,'       @       ,' 3      |       ,'       |       ,'
///       |   8 @'      18 |     ,'          |     ,' [1]  ___|     ,'
///       |   ,'           |   ,@ 10         |   ,'      ,'4,'|   ,'
///       | ,'             | ,'              | ,'        ~~~  | ,'
///       @-------@--------@'                +----------------+'
///     1         9         2
///
///
///                  Edges (12)
///
///                         7
///                 +----------------+
///               ,'|              ,'|
///           4 ,'  |8          6,'  |
///           ,'    |          ,'    |
///         ,'      |   5    ,'      |11
///       +'===============+'        |
///       |         |      |         |
///       |         |      |  3      |
///       |         .- - - | -  - - -+
///      9|       ,'       |       ,'
///       |    0,'         |10   ,'
///       |   ,'           |   ,' 2
///       | ,'             | ,'
///       +----------------+'
///               1
///
pub struct Block {
    group: usize,             // group of all elements in this block
    ndim: usize,              // space dimension
    npoint: usize,            // number of points (4, 8, or 20)
    nedge: usize,             // number of edges (4 or 12)
    nface: usize,             // number of faces (4 or 6)
    coords: Matrix,           // coordinates of points (npoint, ndim)
    point_groups: Vec<usize>, // point groups (npoint)
    edge_groups: Vec<usize>,  // edge groups (nedge)
    face_groups: Vec<usize>,  // face groups (nface)
    num_div: Vec<usize>,      // number of divisions along each dim (ndim)
    weights: Vec<Vec<f64>>,   // weights along each dimension (ndim, nweight)
    sum_weights: Vec<f64>,    // sum of weights along each dimension (ndim)

    // maps side to constraint (num_sides)
    constraints: HashMap<Constraint, ConstraintData>,
}

impl Block {
    pub fn new(group: usize, kind: BlockKind) -> Self {
        let (ndim, npoint, nedge, nface) = match kind {
            BlockKind::Qua4 => (2, 4, 4, 0),
            BlockKind::Qua8 => (2, 8, 4, 0),
            BlockKind::Hex8 => (3, 8, 12, 6),
            BlockKind::Hex20 => (3, 20, 12, 6),
        };
        Block {
            group,
            ndim,
            npoint,
            nedge,
            nface,
            coords: Matrix::new(npoint, ndim),
            point_groups: vec![0; npoint],
            edge_groups: vec![0; nedge],
            face_groups: vec![0; nface],
            num_div: vec![0; ndim],
            weights: vec![Vec::new(); ndim],
            sum_weights: vec![0.0; ndim],
            constraints: HashMap::new(),
        }
    }

    pub fn set_point_2d(&mut self, m: usize, group: usize, x: f64, y: f64) -> &mut Self {
        assert_eq!(self.ndim, 2);
        assert!(m < self.npoint);
        self.point_groups[m] = group;
        self.coords[m][0] = x;
        self.coords[m][1] = y;
        self
    }

    pub fn set_point_3d(&mut self, m: usize, group: usize, x: f64, y: f64, z: f64) -> &mut Self {
        assert_eq!(self.ndim, 3);
        assert!(m < self.npoint);
        self.point_groups[m] = group;
        self.coords[m][0] = x;
        self.coords[m][1] = y;
        self.coords[m][2] = z;
        self
    }

    pub fn set_coords<'a, T, U>(&mut self, coords: &'a T) -> &mut Self
    where
        T: AsArray2D<'a, U>,
        U: 'a + Into<f64>,
    {
        let (nrow, ncol) = coords.size();
        assert_eq!(nrow, self.npoint);
        assert_eq!(ncol, self.ndim);
        for i in 0..nrow {
            for j in 0..ncol {
                self.coords[i][j] = coords.at(i, j).into();
            }
        }
        self
    }

    pub fn set_point_group(&mut self, m: usize, group: usize) -> &mut Self {
        assert!(m < self.npoint);
        self.point_groups[m] = group;
        self
    }
}

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

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

    #[test]
    fn new_works() {
        let block = Block::new(1, BlockKind::Qua4);
        assert_eq!(block.group, 1);
        assert_eq!(block.ndim, 2);
        assert_eq!(block.npoint, 4);
        assert_eq!(block.nedge, 4);
        assert_eq!(block.nface, 0);
    }

    #[test]
    fn set_point_2d_works() {
        let mut block = Block::new(1, BlockKind::Qua4);
        block
            .set_point_2d(0, 1, 0.0, 0.0)
            .set_point_2d(1, 2, 2.0, 0.0)
            .set_point_2d(2, 3, 2.0, 2.0)
            .set_point_2d(3, 4, 0.0, 2.0);
        assert_eq!(
            format!("{}", block.coords),
            "┌     ┐\n\
             │ 0 0 │\n\
             │ 2 0 │\n\
             │ 2 2 │\n\
             │ 0 2 │\n\
             └     ┘"
        );
    }

    #[test]
    fn set_point_3d_works() {
        let mut block = Block::new(1, BlockKind::Hex8);
        block
            .set_point_3d(0, 1, 0.0, 0.0, 0.0)
            .set_point_3d(1, 2, 2.0, 0.0, 0.0)
            .set_point_3d(2, 3, 2.0, 2.0, 0.0)
            .set_point_3d(3, 4, 0.0, 2.0, 0.0)
            .set_point_3d(4, 1, 0.0, 0.0, 2.0)
            .set_point_3d(5, 2, 2.0, 0.0, 2.0)
            .set_point_3d(6, 3, 2.0, 2.0, 2.0)
            .set_point_3d(7, 4, 0.0, 2.0, 2.0);
        assert_eq!(
            format!("{}", block.coords),
            "┌       ┐\n\
             │ 0 0 0 │\n\
             │ 2 0 0 │\n\
             │ 2 2 0 │\n\
             │ 0 2 0 │\n\
             │ 0 0 2 │\n\
             │ 2 0 2 │\n\
             │ 2 2 2 │\n\
             │ 0 2 2 │\n\
             └       ┘"
        );
    }

    #[test]
    fn set_coords_works() {
        let mut qua4 = Block::new(1, BlockKind::Qua4);
        #[rustfmt::skip]
        qua4.set_coords(&[
            [0.0, 0.0],
            [2.0, 0.0],
            [2.0, 2.0],
            [0.0, 2.0],
        ]);
        assert_eq!(
            format!("{}", qua4.coords),
            "┌     ┐\n\
             │ 0 0 │\n\
             │ 2 0 │\n\
             │ 2 2 │\n\
             │ 0 2 │\n\
             └     ┘"
        );

        let mut hex8 = Block::new(1, BlockKind::Hex8);
        #[rustfmt::skip]
        hex8.set_coords(&[
            [0.0, 0.0, 0.0],
            [2.0, 0.0, 0.0],
            [2.0, 2.0, 0.0],
            [0.0, 2.0, 0.0],
            [0.0, 0.0, 2.0],
            [2.0, 0.0, 2.0],
            [2.0, 2.0, 2.0],
            [0.0, 2.0, 2.0],
        ]);
        assert_eq!(
            format!("{}", hex8.coords),
            "┌       ┐\n\
             │ 0 0 0 │\n\
             │ 2 0 0 │\n\
             │ 2 2 0 │\n\
             │ 0 2 0 │\n\
             │ 0 0 2 │\n\
             │ 2 0 2 │\n\
             │ 2 2 2 │\n\
             │ 0 2 2 │\n\
             └       ┘"
        );
    }

    #[test]
    fn set_point_group_works() {
        let mut block = Block::new(1, BlockKind::Qua4);
        block.set_point_group(0, 111);
        assert_eq!(block.point_groups, &[111, 0, 0, 0]);
    }
}
<|endoftext|>


<commit_before>use super::ffi::*;
use super::ffi::ShShaderOutput::*;
use super::ffi::ShShaderSpec::*;

use std::default;
use std::ffi::CStr;
use std::ffi::CString;
use std::mem;
use std::sync::Mutex;
use std::os::raw::c_char;

lazy_static! {
    static ref CONSTRUCT_COMPILER_LOCK: Mutex<()> = {
        Mutex::new(())
    };
}

pub fn initialize() -> Result<(), &'static str> {
    if unsafe { GLSLangInitialize() } == 0 {
        Err("Couldn't initialize GLSLang")
    } else {
        Ok(())
    }
}

pub fn finalize() -> Result<(), &'static str> {
    if unsafe { GLSLangFinalize() } == 0 {
        Err("Couldn't finalize GLSLang")
    } else {
        Ok(())
    }
}

pub trait AsAngleEnum {
    fn as_angle_enum(&self) -> i32;
}

pub enum ShaderSpec {
    Gles2,
    WebGL,
    Gles3,
    WebGL2,
    WebGL3,
}

impl AsAngleEnum for ShaderSpec {
    #[inline]
    fn as_angle_enum(&self) -> i32 {
        (match *self {
            ShaderSpec::Gles2 => SH_GLES2_SPEC,
            ShaderSpec::WebGL => SH_WEBGL_SPEC,
            ShaderSpec::Gles3 => SH_GLES3_SPEC,
            ShaderSpec::WebGL2 => SH_WEBGL2_SPEC,
            ShaderSpec::WebGL3 => SH_WEBGL3_SPEC,
        }) as i32
    }
}

pub enum Output {
    Essl,
    Glsl,
    GlslCompat,
    GlslCore,
    Glsl130,
    Glsl140,
    Glsl150Core,
    Glsl330Core,
    Glsl400Core,
    Glsl410Core,
    Glsl420Core,
    Glsl430Core,
    Glsl440Core,
    Glsl450Core,
}

impl AsAngleEnum for Output {
    #[inline]
    fn as_angle_enum(&self) -> i32 {
        (match *self {
            Output::Essl => SH_ESSL_OUTPUT,
            Output::Glsl => SH_GLSL_COMPATIBILITY_OUTPUT,
            Output::GlslCompat => SH_GLSL_COMPATIBILITY_OUTPUT,
            Output::GlslCore => SH_GLSL_130_OUTPUT,
            Output::Glsl130 => SH_GLSL_130_OUTPUT,
            Output::Glsl140 => SH_GLSL_140_OUTPUT,
            Output::Glsl150Core => SH_GLSL_150_CORE_OUTPUT,
            Output::Glsl330Core => SH_GLSL_330_CORE_OUTPUT,
            Output::Glsl400Core => SH_GLSL_400_CORE_OUTPUT,
            Output::Glsl410Core => SH_GLSL_410_CORE_OUTPUT,
            Output::Glsl420Core => SH_GLSL_420_CORE_OUTPUT,
            Output::Glsl430Core => SH_GLSL_430_CORE_OUTPUT,
            Output::Glsl440Core => SH_GLSL_440_CORE_OUTPUT,
            Output::Glsl450Core => SH_GLSL_450_CORE_OUTPUT,
        }) as i32
    }
}

pub type BuiltInResources = ShBuiltInResources;

impl default::Default for BuiltInResources {
    fn default() -> BuiltInResources {
        unsafe {
            let mut ret: BuiltInResources = mem::zeroed();
            GLSLangInitBuiltInResources(&mut ret);
            ret
        }
    }
}

impl BuiltInResources {
    #[inline]
    pub fn empty() -> BuiltInResources {
        unsafe { mem::zeroed() }
    }
}

pub struct ShaderValidator {
    handle: ShHandle,
}

impl ShaderValidator {
    /// Create a new ShaderValidator instance
    /// NB: To call this you should have called first
    /// initialize()
    pub fn new(shader_type: u32,
               spec: ShaderSpec,
               output: Output,
               resources: &BuiltInResources) -> Option<ShaderValidator> {
        // GLSLangConstructCompiler is non-thread safe because it internally calls TCache::getType()
        // which writes/reads a std::map<T> with no locks.
        let _guard = CONSTRUCT_COMPILER_LOCK.lock().unwrap();
        let handle = unsafe {
            GLSLangConstructCompiler(shader_type, spec.as_angle_enum(), output.as_angle_enum(), resources)
        };

        if handle.is_null() {
            return None;
        }

        Some(ShaderValidator {
            handle: handle,
        })
    }

    #[inline]
    pub fn for_webgl(shader_type: u32,
                     output: Output,
                     resources: &BuiltInResources) -> Option<ShaderValidator> {
        Self::new(shader_type, ShaderSpec::WebGL, output, resources)
    }

    #[inline]
    pub fn for_webgl2(shader_type: u32,
                      output: Output,
                      resources: &BuiltInResources) -> Option<ShaderValidator> {
        Self::new(shader_type, ShaderSpec::WebGL2, output, resources)
    }

    pub fn compile(&self, strings: &[&str], options: ShCompileOptions) -> Result<(), &'static str> {
        let mut cstrings = Vec::with_capacity(strings.len());

        for s in strings.iter() {
            cstrings.push(try!(CString::new(*s).map_err(|_| "Found invalid characters")))
        }

        let cptrs: Vec<_> = cstrings.iter().map(|s| s.as_ptr()).collect();

        if unsafe { GLSLangCompile(self.handle,
                                   cptrs.as_ptr() as *const *const c_char,
                                   cstrings.len(),
                                   options) } == 0 {
            return Err("Couldn't compile shader")
        }
        Ok(())
    }

    pub fn object_code(&self) -> String {
        unsafe {
            let c_str = CStr::from_ptr(GLSLangGetObjectCode(self.handle));
            c_str.to_string_lossy().into_owned()
        }
    }

    pub fn info_log(&self) -> String {
        unsafe {
            let c_str = CStr::from_ptr(GLSLangGetInfoLog(self.handle));
            c_str.to_string_lossy().into_owned()
        }
    }

    pub fn compile_and_translate(&self, strings: &[&str]) -> Result<String, &'static str> {
        let options = SH_VALIDATE | SH_OBJECT_CODE |
                      SH_EMULATE_ABS_INT_FUNCTION | // To workaround drivers
                      SH_EMULATE_ISNAN_FLOAT_FUNCTION | // To workaround drivers
                      SH_EMULATE_ATAN2_FLOAT_FUNCTION | // To workaround drivers
                      SH_CLAMP_INDIRECT_ARRAY_BOUNDS |
                      SH_INIT_GL_POSITION |
                      SH_ENFORCE_PACKING_RESTRICTIONS |
                      SH_LIMIT_CALL_STACK_DEPTH;

        // Todo(Mortimer): Add SH_TIMING_RESTRICTIONS to options when the implementations gets better
        // Right now SH_TIMING_RESTRICTIONS is experimental
        // and doesn't support user callable functions in shaders

        try!(self.compile(strings, options));
        Ok(self.object_code())
    }
}

impl Drop for ShaderValidator {
    fn drop(&mut self) {
        unsafe {
            GLSLangDestructCompiler(self.handle)
        }
    }
}
<commit_msg>Enable expression complexity limits.<commit_after>use super::ffi::*;
use super::ffi::ShShaderOutput::*;
use super::ffi::ShShaderSpec::*;

use std::default;
use std::ffi::CStr;
use std::ffi::CString;
use std::mem;
use std::sync::Mutex;
use std::os::raw::c_char;

lazy_static! {
    static ref CONSTRUCT_COMPILER_LOCK: Mutex<()> = {
        Mutex::new(())
    };
}

pub fn initialize() -> Result<(), &'static str> {
    if unsafe { GLSLangInitialize() } == 0 {
        Err("Couldn't initialize GLSLang")
    } else {
        Ok(())
    }
}

pub fn finalize() -> Result<(), &'static str> {
    if unsafe { GLSLangFinalize() } == 0 {
        Err("Couldn't finalize GLSLang")
    } else {
        Ok(())
    }
}

pub trait AsAngleEnum {
    fn as_angle_enum(&self) -> i32;
}

pub enum ShaderSpec {
    Gles2,
    WebGL,
    Gles3,
    WebGL2,
    WebGL3,
}

impl AsAngleEnum for ShaderSpec {
    #[inline]
    fn as_angle_enum(&self) -> i32 {
        (match *self {
            ShaderSpec::Gles2 => SH_GLES2_SPEC,
            ShaderSpec::WebGL => SH_WEBGL_SPEC,
            ShaderSpec::Gles3 => SH_GLES3_SPEC,
            ShaderSpec::WebGL2 => SH_WEBGL2_SPEC,
            ShaderSpec::WebGL3 => SH_WEBGL3_SPEC,
        }) as i32
    }
}

pub enum Output {
    Essl,
    Glsl,
    GlslCompat,
    GlslCore,
    Glsl130,
    Glsl140,
    Glsl150Core,
    Glsl330Core,
    Glsl400Core,
    Glsl410Core,
    Glsl420Core,
    Glsl430Core,
    Glsl440Core,
    Glsl450Core,
}

impl AsAngleEnum for Output {
    #[inline]
    fn as_angle_enum(&self) -> i32 {
        (match *self {
            Output::Essl => SH_ESSL_OUTPUT,
            Output::Glsl => SH_GLSL_COMPATIBILITY_OUTPUT,
            Output::GlslCompat => SH_GLSL_COMPATIBILITY_OUTPUT,
            Output::GlslCore => SH_GLSL_130_OUTPUT,
            Output::Glsl130 => SH_GLSL_130_OUTPUT,
            Output::Glsl140 => SH_GLSL_140_OUTPUT,
            Output::Glsl150Core => SH_GLSL_150_CORE_OUTPUT,
            Output::Glsl330Core => SH_GLSL_330_CORE_OUTPUT,
            Output::Glsl400Core => SH_GLSL_400_CORE_OUTPUT,
            Output::Glsl410Core => SH_GLSL_410_CORE_OUTPUT,
            Output::Glsl420Core => SH_GLSL_420_CORE_OUTPUT,
            Output::Glsl430Core => SH_GLSL_430_CORE_OUTPUT,
            Output::Glsl440Core => SH_GLSL_440_CORE_OUTPUT,
            Output::Glsl450Core => SH_GLSL_450_CORE_OUTPUT,
        }) as i32
    }
}

pub type BuiltInResources = ShBuiltInResources;

impl default::Default for BuiltInResources {
    fn default() -> BuiltInResources {
        unsafe {
            let mut ret: BuiltInResources = mem::zeroed();
            GLSLangInitBuiltInResources(&mut ret);
            ret
        }
    }
}

impl BuiltInResources {
    #[inline]
    pub fn empty() -> BuiltInResources {
        unsafe { mem::zeroed() }
    }
}

pub struct ShaderValidator {
    handle: ShHandle,
}

impl ShaderValidator {
    /// Create a new ShaderValidator instance
    /// NB: To call this you should have called first
    /// initialize()
    pub fn new(shader_type: u32,
               spec: ShaderSpec,
               output: Output,
               resources: &BuiltInResources) -> Option<ShaderValidator> {
        // GLSLangConstructCompiler is non-thread safe because it internally calls TCache::getType()
        // which writes/reads a std::map<T> with no locks.
        let _guard = CONSTRUCT_COMPILER_LOCK.lock().unwrap();
        let handle = unsafe {
            GLSLangConstructCompiler(shader_type, spec.as_angle_enum(), output.as_angle_enum(), resources)
        };

        if handle.is_null() {
            return None;
        }

        Some(ShaderValidator {
            handle: handle,
        })
    }

    #[inline]
    pub fn for_webgl(shader_type: u32,
                     output: Output,
                     resources: &BuiltInResources) -> Option<ShaderValidator> {
        Self::new(shader_type, ShaderSpec::WebGL, output, resources)
    }

    #[inline]
    pub fn for_webgl2(shader_type: u32,
                      output: Output,
                      resources: &BuiltInResources) -> Option<ShaderValidator> {
        Self::new(shader_type, ShaderSpec::WebGL2, output, resources)
    }

    pub fn compile(&self, strings: &[&str], options: ShCompileOptions) -> Result<(), &'static str> {
        let mut cstrings = Vec::with_capacity(strings.len());

        for s in strings.iter() {
            cstrings.push(try!(CString::new(*s).map_err(|_| "Found invalid characters")))
        }

        let cptrs: Vec<_> = cstrings.iter().map(|s| s.as_ptr()).collect();

        if unsafe { GLSLangCompile(self.handle,
                                   cptrs.as_ptr() as *const *const c_char,
                                   cstrings.len(),
                                   options) } == 0 {
            return Err("Couldn't compile shader")
        }
        Ok(())
    }

    pub fn object_code(&self) -> String {
        unsafe {
            let c_str = CStr::from_ptr(GLSLangGetObjectCode(self.handle));
            c_str.to_string_lossy().into_owned()
        }
    }

    pub fn info_log(&self) -> String {
        unsafe {
            let c_str = CStr::from_ptr(GLSLangGetInfoLog(self.handle));
            c_str.to_string_lossy().into_owned()
        }
    }

    pub fn compile_and_translate(&self, strings: &[&str]) -> Result<String, &'static str> {
        let options = SH_VALIDATE | SH_OBJECT_CODE |
                      SH_EMULATE_ABS_INT_FUNCTION | // To workaround drivers
                      SH_EMULATE_ISNAN_FLOAT_FUNCTION | // To workaround drivers
                      SH_EMULATE_ATAN2_FLOAT_FUNCTION | // To workaround drivers
                      SH_CLAMP_INDIRECT_ARRAY_BOUNDS |
                      SH_INIT_GL_POSITION |
                      SH_ENFORCE_PACKING_RESTRICTIONS |
                      SH_LIMIT_EXPRESSION_COMPLEXITY |
                      SH_LIMIT_CALL_STACK_DEPTH;

        // Todo(Mortimer): Add SH_TIMING_RESTRICTIONS to options when the implementations gets better
        // Right now SH_TIMING_RESTRICTIONS is experimental
        // and doesn't support user callable functions in shaders

        try!(self.compile(strings, options));
        Ok(self.object_code())
    }
}

impl Drop for ShaderValidator {
    fn drop(&mut self) {
        unsafe {
            GLSLangDestructCompiler(self.handle)
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::Path;

use rand::Rng;

use irc;

pub struct HP<'r> {
    name: &'r str,
    words: Vec<String>,
    rng: rand::ThreadRng
}

#[derive(Debug, PartialEq)]
pub enum Command {
    StartGame(String, char, String)
}

fn read_list(path: &str) -> Vec<String> {
    let f = File::open(&Path::new(path)).unwrap();
    let file = BufReader::new(&f);
    let mut lines = Vec::new();
    for line in file.lines() {
        let l = line.unwrap();
        lines.push(l.clone());
    }
    return lines;
}

pub fn init<'r>(name: &'r str, path: &str) -> HP<'r> {
    let words = read_list(path);
    assert!(words.len() > 0);
    return HP { name: name, words: words, rng: rand::thread_rng() };
}

impl<'r> HP<'r> {
    fn pick_word(&mut self) -> (&String, char) {
        let word = self.rng.choose(&self.words).unwrap();
        let chars : Vec<char> = word.chars().collect();
        let chr = self.rng.choose(&chars).unwrap().clone();
        return (word, chr);
    }

    pub fn execute(&mut self, parts: &[&str]) -> Vec<Command> {
        if parts.len() == 0 {
            return vec![];
        } else if parts[0] == self.name {
            let exp = format!("se {}", &self.name);
            let (word, chr) = self.pick_word();
            return vec![Command::StartGame(word.to_string(), chr, exp)];
        }
        return vec![];
    }
}

impl Command {
    pub fn execute(self, irc: &mut irc::Irc) {
        match self {
            Command::StartGame(word, chr, exp) => {
                let _ = send!(
                    irc, "PRIVMSG Putkamon :#ohjusputka:hp \"{}\" {} \"{}\"\r\n",
                    word, chr, exp
                );
            },
        }
    }
}

mod test {
    #[allow(unused_imports)]
    use super::*;
    #[allow(unused_imports)]
    use rand;

    #[test]
    fn test_execute() {
        let mut hp = HP {
            name: "test",
            words: vec!["duck".to_string()],
            rng: rand::thread_rng()
        };
        assert_eq!(hp.execute(&[]), []);
        assert_eq!(hp.execute(&["does not exist"]), []);

        let commands = hp.execute(&["test"]);
        match commands[0] {
            Command::StartGame(ref word, _, ref exp) => {
                assert_eq!(word, "duck");
                assert_eq!(exp, "se test");
            }
        }
    }

    #[test]
    fn test_init() {
        let mut hp = init("word", "fixtures/test_word_list.txt");
        assert!(hp.execute(&["...."]).is_empty());
        assert!(!hp.execute(&["word"]).is_empty());
    }
}
<commit_msg>Add commentary<commit_after>extern crate rand;

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::Path;

use rand::Rng;

use irc;

pub struct HP<'r> {
    name: &'r str,
    words: Vec<String>,
    rng: rand::ThreadRng
}

#[derive(Debug, PartialEq)]
pub enum Command {
    StartGame(String, char, String)
}

fn read_list(path: &str) -> Vec<String> {
    let f = File::open(&Path::new(path)).unwrap();
    let file = BufReader::new(&f);
    let mut lines = Vec::new();
    for line in file.lines() {
        let l = line.unwrap();
        lines.push(l.clone());
    }
    return lines;
}

pub fn init<'r>(name: &'r str, path: &str) -> HP<'r> {
    let words = read_list(path);
    assert!(words.len() > 0);
    return HP { name: name, words: words, rng: rand::thread_rng() };
}

// The idea: HP.execute takes the incoming command and produces a vector of
// internal commands, which are executed with Command.execute.
// XXX(miikka) This naming might require some work. Two commands, two executes?

impl<'r> HP<'r> {
    fn pick_word(&mut self) -> (&String, char) {
        let word = self.rng.choose(&self.words).unwrap();
        let chars : Vec<char> = word.chars().collect();
        let chr = self.rng.choose(&chars).unwrap().clone();
        return (word, chr);
    }

    pub fn execute(&mut self, parts: &[&str]) -> Vec<Command> {
        if parts.len() == 0 {
            return vec![];
        } else if parts[0] == self.name {
            let exp = format!("se {}", &self.name);
            let (word, chr) = self.pick_word();
            return vec![Command::StartGame(word.to_string(), chr, exp)];
        }
        return vec![];
    }
}

impl Command {
    pub fn execute(self, irc: &mut irc::Irc) {
        match self {
            Command::StartGame(word, chr, exp) => {
                let _ = send!(
                    irc, "PRIVMSG Putkamon :#ohjusputka:hp \"{}\" {} \"{}\"\r\n",
                    word, chr, exp
                );
            },
        }
    }
}

mod test {
    #[allow(unused_imports)]
    use super::*;
    #[allow(unused_imports)]
    use rand;

    #[test]
    fn test_execute() {
        let mut hp = HP {
            name: "test",
            words: vec!["duck".to_string()],
            rng: rand::thread_rng()
        };
        assert_eq!(hp.execute(&[]), []);
        assert_eq!(hp.execute(&["does not exist"]), []);

        let commands = hp.execute(&["test"]);
        match commands[0] {
            Command::StartGame(ref word, _, ref exp) => {
                assert_eq!(word, "duck");
                assert_eq!(exp, "se test");
            }
        }
    }

    #[test]
    fn test_init() {
        let mut hp = init("word", "fixtures/test_word_list.txt");
        assert!(hp.execute(&["...."]).is_empty());
        assert!(!hp.execute(&["word"]).is_empty());
    }
}
<|endoftext|>


<commit_before>//! Implements the extraction of the principal variation from the
//! transposition table.

use std::cmp::min;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    ///
    /// The value is from the point of view of player that has the
    /// move in the starting position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}

/// Extracts the principal variation for a given position from the
/// transposition table.
///
/// The principal variation (PV) is the sequence of moves that the
/// engine considers best and therefore expects to be played.
pub fn extract_pv<T: HashTable, N: SearchNode>(tt: &T, position: &N) -> Variation {
    let mut p = position.clone();
    let mut our_turn = true;
    let mut moves = Vec::with_capacity(32);
    let mut root_value = VALUE_UNKNOWN;
    let mut value = VALUE_MAX;
    let mut bound = BOUND_UPPER;
    let mut depth = DEPTH_MAX + 1;

    'move_extraction: while let Some(e) = tt.probe(p.hash()) {
        depth = min(depth - 1, e.depth());

        if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
            // In half of the cases the value is from other side's perspective.
            if our_turn {
                value = e.value();
                bound = e.bound();
            } else {
                value = -e.value();
                bound = match e.bound() {
                    BOUND_UPPER => BOUND_LOWER,
                    BOUND_LOWER => BOUND_UPPER,
                    b => b,
                };
            }
            assert!(value != VALUE_UNKNOWN);

            // Set the root value on the first iteration.
            if root_value == VALUE_UNKNOWN {
                root_value = value;
            }

            // Consider adding current entry's hash move to the
            // PV. There are 3 conditions for this:
            //
            // 1) The depth limit has not been reached yet.
            // 2) The move is either best move or a refutation move.
            // 3) The value has not diverged from the root value.
            if depth > 0 && e.bound() & BOUND_LOWER != 0 &&
               match root_value {
                v if v < VALUE_EVAL_MIN => v as isize == value as isize + moves.len() as isize,
                v if v > VALUE_EVAL_MAX => v as isize == value as isize - moves.len() as isize,
                v => v == value,
            } {
                // Verify that the hash move is legal.
                if let Some(m) = p.try_move_digest(e.move_digest()) {
                    if p.do_move(m) {
                        moves.push(m);

                        // Note: we stop expanding the PV on refutation moves.
                        if e.bound() == BOUND_EXACT {
                            our_turn = !our_turn;
                            continue 'move_extraction;
                        }
                    }
                }
            }
        }
        break 'move_extraction;
    }

    Variation {
        value: if root_value != VALUE_UNKNOWN {
            root_value
        } else {
            value
        },
        bound: bound,
        moves: moves,
    }
}
<commit_msg>fix a subtle bug -- not showing BOUND_LOWER moves.<commit_after>//! Implements the extraction of the principal variation from the
//! transposition table.

use std::cmp::min;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    ///
    /// The value is from the point of view of player that has the
    /// move in the starting position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}

/// Extracts the principal variation for a given position from the
/// transposition table.
///
/// The principal variation (PV) is the sequence of moves that the
/// engine considers best and therefore expects to be played.
pub fn extract_pv<T: HashTable, N: SearchNode>(tt: &T, position: &N) -> Variation {
    let mut p = position.clone();
    let mut our_turn = true;
    let mut moves = Vec::with_capacity(32);
    let mut root_value = VALUE_UNKNOWN;
    let mut value = VALUE_MAX;
    let mut bound = BOUND_UPPER;
    let mut depth = DEPTH_MAX + 1;

    'move_extraction: while let Some(e) = tt.probe(p.hash()) {
        depth = min(depth - 1, e.depth());

        if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
            // In half of the cases the value is from other side's perspective.
            if our_turn {
                value = e.value();
                bound = e.bound();
            } else {
                value = -e.value();
                bound = match e.bound() {
                    BOUND_UPPER => BOUND_LOWER,
                    BOUND_LOWER => BOUND_UPPER,
                    b => b,
                };
            }
            assert!(value != VALUE_UNKNOWN);

            // Set the root value on the first iteration.
            if root_value == VALUE_UNKNOWN {
                root_value = value;
            }

            // Consider adding current entry's hash move to the
            // PV. There are 2 conditions for this:
            //
            // 1) The depth limit has not been reached yet.
            // 2) The value has not diverged from the root value.
            if depth > 0 &&
               match root_value {
                v if v < VALUE_EVAL_MIN => v as isize == value as isize + moves.len() as isize,
                v if v > VALUE_EVAL_MAX => v as isize == value as isize - moves.len() as isize,
                v => v == value,
            } {
                // Verify that the hash move is legal.
                if let Some(m) = p.try_move_digest(e.move_digest()) {
                    if p.do_move(m) {
                        moves.push(m);

                        // Note: we stop expanding the PV on refutation moves.
                        if e.bound() == BOUND_EXACT {
                            our_turn = !our_turn;
                            continue 'move_extraction;
                        }
                    }
                }
            }
        }
        break 'move_extraction;
    }

    Variation {
        value: if root_value != VALUE_UNKNOWN {
            root_value
        } else {
            value
        },
        bound: bound,
        moves: moves,
    }
}
<|endoftext|>


<commit_before>use base::{MatBase, Mat, SubAssign};

struct QR {
    // TODO: Store in a single mat
    Q: Mat,
    R: Mat,
}

impl QR {
    pub fn of(A: &Mat) -> QR {
        if !A.is_square() {
            panic!("QR must apply to square matrix");
        }
        let mut R = A.clone();
        let mut Q = Mat::ident(A.r);

        let mut e1 = Mat::zero(R.rows(), 1);

        // All I want for christmas is a smarter borrow checker
        let w = {
            let x = R.col(0);
            e1[(0, 0)] = x.norm();
            let mut v = x - e1;
            v.normalize();
            v
        };

        // H := I - 2ww'
        // R := H * R
        let tmp = &w.t() * &R;  // Borrow checker limitations
        R.sub_assign(&w * tmp * 2.0);

        //R.block_lr() -= 2 * v * (v.t() * R.block_lr());

        QR{Q: Q, R: R}
    }
}

#[test]
fn test_qr_simple() {
    let A = Mat::from_slice(3, 3, &[0.0, 1.0, 1.0,
                                    1.0, 1.0, 2.0,
                                    0.0, 0.0, 3.0]);
    let qr = QR::of(&A);

    let Q = Mat::from_slice(3, 3, &[0.0, 1.0, 0.0,
                                    1.0, 0.0, 0.0,
                                    0.0, 0.0, 1.0]);
    let R = Mat::from_slice(3, 3, &[1.0, 1.0, 2.0,
                                    0.0, 1.0, 1.0,
                                    0.0, 0.0, 3.0]);
}
<commit_msg>One round of QR working<commit_after>use base::{MatBase, Mat, SubAssign};

struct QR {
    // TODO: Store in a single mat
    Q: Mat,
    R: Mat,
}

impl QR {
    pub fn of(A: &Mat) -> QR {
        if !A.is_square() {
            panic!("QR must apply to square matrix");
        }
        let mut R = A.clone();
        let mut Q = Mat::ident(A.r);

        println!("inital Q:\n{}", Q);
        println!("inital R:\n{}", R);

        let mut e1 = Mat::zero(R.rows(), 1);

        // All I want for christmas is a smarter borrow checker
        let w = {
            let x = R.col(0);
            e1[(0, 0)] = x.norm();
            println!("|x| * e = \n{}", e1);
            let mut v = x - e1;
            println!("v = \n{}", v);
            v.normalize();
            v
        };

        println!("w = \n{}", w);

        let H = Mat::ident(R.rows()) - &w * &w.t() * 2.0;
        println!("H = \n{}", H);

        // H := I - 2ww'
        // R := H * R
        let tmp = &w.t() * &R;  // Borrow checker limitations (for R)
        R.sub_assign(&w * tmp * 2.0);
        //R.block_lr() -= 2 * v * (v.t() * R.block_lr());

        // Q := Q * H
        let tmp = &Q * &w;
        Q.sub_assign(tmp * w.t() * 2.0);

        println!("Q after:\n{}", Q);
        println!("R after:\n{}", R);
        println!("Q*R after:\n{}", &Q * &R);

        // A = QR
        // Q' * A = R

        QR{Q: Q, R: R}
    }
}

#[test]
fn test_qr_simple() {
    let A = Mat::from_slice(3, 3, &[0.0, 1.0, 1.0,
                                    1.0, 1.0, 2.0,
                                    0.0, 0.0, 3.0]);
    let qr = QR::of(&A);

    let Q = Mat::from_slice(3, 3, &[0.0, 1.0, 0.0,
                                    1.0, 0.0, 0.0,
                                    0.0, 0.0, 1.0]);
    let R = Mat::from_slice(3, 3, &[1.0, 1.0, 2.0,
                                    0.0, 1.0, 1.0,
                                    0.0, 0.0, 3.0]);
}

#[test]
fn test_qr_wikipedia() {
    let A = Mat::from_slice(3, 3, &[12.0, -51.0, 4.0,
                                    6.0, 167.0, -68.0,
                                    -4.0, 24.0, -41.0]);
    let qr = QR::of(&A);
}
<|endoftext|>