<commit_before>use commands::{Command, CommandExecutor};
use std::error;
use std::sync::Arc;
use errors::anoncreds::AnoncredsError;

pub struct AnoncredsAPI {
    command_executor: Arc<CommandExecutor>,
}

impl AnoncredsAPI {
    pub fn new(command_executor: Arc<CommandExecutor>) -> AnoncredsAPI {
        AnoncredsAPI { command_executor: command_executor }
    }

    pub fn create_master_secret(cb: Box<Fn(Result<(String), AnoncredsError>) + Send>) {

    }

    pub fn create_keys(schema: String,
                       cb: Box<Fn(Result<((String, String)), AnoncredsError>) + Send>) {

    }

    pub fn create_context_attribute(i_a: String, user_id: String,
                                    cb: Box<Fn(Result<(String), AnoncredsError>) + Send>) {

    }

    pub fn issue_accumulator(schema: String, i_a: String, l: String,
                             public_key_revocation: String,
                             cb: Box<Fn(
                                 Result<((String, String, String, String)),
                                     AnoncredsError>
                             ) + Send>) {

    }

    pub fn issue_claim(attributes: String, accumulator: String,i_a: String, i: String,
                       claim_request: String, context_attribute: String, public_key: String,
                       secret_key: String, public_key_revocation: String,
                       secret_key_revocation: String, tails: String,
                       secret_key_accumulator: String,
                       cb: Box<Fn(Result<(String, String), AnoncredsError>) + Send>) {

    }

    pub fn create_claim_request(master_secret: String, public_key: String,
                                public_key_revocation: String, request_non_revocation: String,
                                cb: Box<Fn(Result<(String), AnoncredsError>) + Send>) {

    }

    pub fn create_proof(proof_input: String, nonce: String, claims: String,
                        public_key_revocation: String, accum: String, public_key: String,
                        master_secret: String,
                        cb: Box<Fn(Result<(String, String), AnoncredsError>) + Send>) {

    }

    pub fn verify_proof(proof_input: String, proof: String, revealed_attributes: String,
                        nonce: String, public_key_revocation: String,
                        public_key_accumulator: String, accumulator: String,
                        public_key: String, attributes: String,
                        cb: Box<Fn(Result<(String), AnoncredsError>) + Send>) {

    }
}

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

    #[test]
    fn anoncreds_api_can_be_created() {
        let anoncreds_api = AnoncredsAPI::new(Arc::new(CommandExecutor::new()));
        assert! (true, "No crashes on AnoncredsAPI::new");
    }

    #[test]
    fn anoncredsn_api_can_be_dropped() {
        fn drop_test() {
            let anoncreds_api = AnoncredsAPI::new(Arc::new(CommandExecutor::new()));
        }

        drop_test();
        assert! (true, "No crashes on AnoncredsAPI::drop");
    }
}<commit_msg>Added documentation<commit_after>use commands::{Command, CommandExecutor};
use std::error;
use std::sync::Arc;
use errors::anoncreds::AnoncredsError;

pub struct AnoncredsAPI {
    command_executor: Arc<CommandExecutor>,
}

impl AnoncredsAPI {
    pub fn new(command_executor: Arc<CommandExecutor>) -> AnoncredsAPI {
        AnoncredsAPI { command_executor: command_executor }
    }

    /// Creates master secret key for prover.
    ///
    /// #Params
    /// cb: Callback that takes command result as a parameter.
    ///
    /// #Returns
    /// Master secret key as a String.
    ///
    /// #Errors
    /// No method specific errors.
    /// See `AnoncredsError` docs for common errors description.
    pub fn create_master_secret(cb: Box<Fn(Result<(String), AnoncredsError>) + Send>) {
        unimplemented!();
    }

    /// Creates public/private keys pair for issuer.
    ///
    /// #Params
    /// schema: claim definition schema as a byte array.
    /// cb: Callback that takes command result as a parameter.
    ///
    /// #Returns
    /// Tuple of
    /// (Public primary key, Secret Key, Public non-revocation key, Secret non-revocation key)
    /// as a String.
    ///
    /// #Errors
    /// No method specific errors.
    /// See `AnoncredsError` docs for common errors description.
    pub fn create_key_pair(schema: &[&u8],
                       cb: Box<Fn(
                           Result<((String, String, String, String)), AnoncredsError>) + Send>) {
        unimplemented!();
    }

    pub fn create_context_attribute(i_a: String, user_id: String,
                                    cb: Box<Fn(Result<(String), AnoncredsError>) + Send>) {

    }

    /// Issues accumulator.
    ///
    /// #Params
    /// schema: claim definition schema as a byte array.
    /// accumulator_id: accumulator id as a byte array.
    /// max_claims: maximum number of claims within accumulator as a byte array.
    /// public_key_non_revocation: non-revocation public key as a byte array.
    /// cb: Callback that takes command result as a parameter.
    ///
    /// #Returns
    /// Tuple of (Accumulator, Tails, Accumulator public key, Accumulator secret key) as a String.
    ///
    /// #Errors
    /// No method specific errors.
    /// See `AnoncredsError` docs for common errors description.
    pub fn issue_accumulator(schema: &[&u8], accumulator_id: &[&u8], max_claims: &[&u8],
                             public_key_non_revocation: &[&u8],
                             cb: Box<Fn(
                                 Result<((String, String, String, String)),
                                     AnoncredsError>
                             ) + Send>) {
        unimplemented!();
    }

    pub fn issue_claim(attributes: String, accumulator: String,i_a: String, i: String,
                       claim_request: String, context_attribute: String, public_key: String,
                       secret_key: String, public_key_revocation: String,
                       secret_key_revocation: String, tails: String,
                       secret_key_accumulator: String,
                       cb: Box<Fn(Result<(String, String), AnoncredsError>) + Send>) {

    }

    /// Creates claim request.
    ///
    /// #Params
    /// master_secret: prover master secret as a byte array.
    /// public_key: issuer public_key as a byte array.
    /// public_key_non_revocation: issuer non-revocation public key as a byte array.
    /// request_non_revocation: whether to request non-revocation claim as a byte array.
    /// cb: Callback that takes command result as a parameter.
    ///
    /// #Returns
    /// Claim request as a String.
    ///
    /// #Errors
    /// No method specific errors.
    /// See `AnoncredsError` docs for common errors description.
    pub fn create_claim_request(master_secret: &[&u8], public_key: &[&u8],
                                public_key_non_revocation: &[&u8], request_non_revocation: &[&u8],
                                cb: Box<Fn(Result<(String), AnoncredsError>) + Send>) {
        unimplemented!();
    }

    pub fn create_proof(proof_input: String, nonce: String, claims: String,
                        public_key_revocation: String, accum: String, public_key: String,
                        master_secret: String,
                        cb: Box<Fn(Result<(String, String), AnoncredsError>) + Send>) {

    }

    pub fn verify_proof(proof_input: String, proof: String, revealed_attributes: String,
                        nonce: String, public_key_revocation: String,
                        public_key_accumulator: String, accumulator: String,
                        public_key: String, attributes: String,
                        cb: Box<Fn(Result<(String), AnoncredsError>) + Send>) {

    }
}

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

    #[test]
    fn anoncreds_api_can_be_created() {
        let anoncreds_api = AnoncredsAPI::new(Arc::new(CommandExecutor::new()));
        assert! (true, "No crashes on AnoncredsAPI::new");
    }

    #[test]
    fn anoncredsn_api_can_be_dropped() {
        fn drop_test() {
            let anoncreds_api = AnoncredsAPI::new(Arc::new(CommandExecutor::new()));
        }

        drop_test();
        assert! (true, "No crashes on AnoncredsAPI::drop");
    }
}<|endoftext|>


<commit_before>use std::any::{ Any, AnyMutRefExt };
use std::boxed::BoxAny;
use typedef::TypeDef;
use metafactory::factory::{ Factory, Getter };

/// Proxy for configuring factory list without caring about the type used.
///
/// This is intended for internal use as injectable container of same-type
/// factories. Used for implementing `one_of` di configuration.
///
/// ```
/// # extern crate metafactory;
/// # extern crate di;
/// use std::any::Any;
/// use metafactory::{ metafactory, argless_as_factory, AsFactoryExt };
/// use di::factory_container::FactoryContainer;
///
/// fn main() {
///     // Let's say we know that we will have bunch of `bool` factories.
///     // In that case we create a new factory container for them:
///     let mut container = FactoryContainer::new::<bool>();
///
///     // Once we actually have our factories, we can inject them into container
///     // without dealing with types. Of course, we should make sure that types
///     // actually match before doing that in the code that is using this
///     // implementation.
///     container.push_items(vec![
///         argless_as_factory(|| true),
///         argless_as_factory(true),
///         argless_as_factory(|| 4i == 8),
///     ]);
///
///     // Once we are ready to use the factory, we can call `new_factory` to
///     // convert all dynamic stuff to statically constructed call hierarchy:
///     let anyed_bool_array_factory = container.new_factory();
///
///     // Of course, that returns it anyed (`Box<Any>`), but we can easily get un-anyed version
///     // by downcasting to `Factory<Vec<bool>>` or using a convenience extension
///     // method for that:
///     let bool_array_factory = anyed_bool_array_factory
///         .as_factory_of::<Vec<bool>>().unwrap();
///
///     // Calling it should produce expected boolean vector:
///     assert_eq!(bool_array_factory.take(), vec![true, true, false]);
///
///     // Of course, factory container itself should be usable as argument
///     // for other factories:
///     let metafactory_all_true = metafactory(|values: Vec<bool>| {
///         values.iter().fold(true, |a, &i| a & i)
///     });
///
///     // We can pass it when constructing a factory for this lambda metafactory:
///     let factory_all_true = metafactory_all_true.new(vec![
///         box bool_array_factory.clone() as Box<Any>
///     ])
///         .ok().unwrap() // check for errors here
///         .as_factory_of::<bool>().unwrap() // same story with downcasting
///     ;
///
///     assert_eq!(factory_all_true.take(), false); // not all values are true
/// }
/// ```
pub struct FactoryContainer<'a> {
    container_type: TypeDef,
    any_getter: Box<Any>,
    do_push_items: |&mut Box<Any>, Vec<Box<Any>>|:'a -> (),
    do_new_factory: |&mut Box<Any>|:'a -> Box<Any>, // Don't worry, it's like Javascript ;)
}

impl<'a> FactoryContainer<'a> {
    /// Create new factory container instance for specified type.
    pub fn new<T: 'static>() -> FactoryContainer<'a> {
        FactoryContainer {
            container_type: TypeDef::of::<Vec<T>>(),
            any_getter: box FactoryVecGetter::<T>::new(),
            do_push_items: |any_getter, items| {
                let getter: &mut FactoryVecGetter<T> = any_getter
                    .downcast_mut::<FactoryVecGetter<T>>().unwrap();

                let len = items.len();
                let items_iter = items.into_iter()
                    .map(|i| *i.downcast::<Factory<T>>().ok().unwrap());

                getter.factories.reserve_exact(len);
                getter.factories.extend(items_iter);
            },
            do_new_factory: |any_getter| {
                let getter: &mut FactoryVecGetter<T> = any_getter
                    .downcast_mut::<FactoryVecGetter<T>>().unwrap();

                box Factory::<Vec<T>>::new(getter.boxed_clone())
            }
        }
    }

    /// Push factory items into container.
    ///
    /// Note that all items should already match container type:
    /// if container was created for `int`, all pushed factories should
    /// produce int. Otherwise this method will panic your app.
    pub fn push_items(&mut self, items: Vec<Box<Any>>) {
        (self.do_push_items)(&mut self.any_getter, items);
    }

    /// Produces factory usable as argument for other factories.
    ///
    /// If inner factories make `int` values, this method will make factory
    /// that makes `Vec<int>` values.
    pub fn new_factory(&mut self) -> Box<Any> {
        (self.do_new_factory)(&mut self.any_getter)
    }

    /// Returns factory type `Vec<T>`.
    ///
    /// ```
    /// use di::factory_container::FactoryContainer;
    ///
    /// let container = FactoryContainer::new::<bool>();
    ///
    /// assert!(container.get_type().is::<Vec<bool>>());
    /// ```
    pub fn get_type(&self) -> TypeDef {
        self.container_type
    }
}

struct FactoryVecGetter<T: 'static> {
    factories: Vec<Factory<T>>,
}

impl<T> Clone for FactoryVecGetter<T> {
    fn clone(&self) -> FactoryVecGetter<T> {
        FactoryVecGetter::<T> {
            factories: self.factories.clone()
        }
    }
}

impl<T> FactoryVecGetter<T> {
    pub fn new() -> FactoryVecGetter<T> {
        FactoryVecGetter::<T> {
            factories: Vec::with_capacity(0)
        }
    }
}

impl<T> Getter<Vec<T>> for FactoryVecGetter<T> {
    fn take(&self) -> Vec<T> {
        // Reserve exact result size.
        let mut items = Vec::<T>::with_capacity(self.factories.len());

        // Construct results from factory results.
        items.extend(
            self.factories.iter()
                .map(|f| f.take())
        );

        // I love Rust.
        items
    }

    fn boxed_clone(&self) -> Box<Getter<Vec<T>> + 'static> {
        box self.clone()
    }
}

#[cfg(test)]
mod test {
    use metafactory::{ argless_as_factory, metafactory, AsFactoryExt };
    use super::{ FactoryContainer };

    #[test]
    fn should_be_usable_as_vec_of_types() {
        let mut container = FactoryContainer::new::<int>();
        container.push_items(vec![
            argless_as_factory(5i),
            argless_as_factory(13i)
        ]);

        let parent_metafactory = metafactory(
            |items: Vec<int>|
                items.into_iter()
                    .map(|i| format!("{}", i))
                    .collect::<Vec<String>>()
                    .connect(", ")
        );

        let parent_getter = parent_metafactory
            .new(vec![
                container.new_factory()
            ]).ok().unwrap()
            .as_factory_of::<String>().unwrap()
        ;

        assert_eq!(parent_getter.take(), "5, 13");
    }
}
<commit_msg>Method to get type can be static.<commit_after>use std::any::{ Any, AnyMutRefExt };
use std::boxed::BoxAny;
use typedef::TypeDef;
use metafactory::factory::{ Factory, Getter };

/// Proxy for configuring factory list without caring about the type used.
///
/// This is intended for internal use as injectable container of same-type
/// factories. Used for implementing `one_of` di configuration.
///
/// ```
/// # extern crate metafactory;
/// # extern crate di;
/// use std::any::Any;
/// use metafactory::{ metafactory, argless_as_factory, AsFactoryExt };
/// use di::factory_container::FactoryContainer;
///
/// fn main() {
///     // Let's say we know that we will have bunch of `bool` factories.
///     // In that case we create a new factory container for them:
///     let mut container = FactoryContainer::new::<bool>();
///
///     // Once we actually have our factories, we can inject them into container
///     // without dealing with types. Of course, we should make sure that types
///     // actually match before doing that in the code that is using this
///     // implementation.
///     container.push_items(vec![
///         argless_as_factory(|| true),
///         argless_as_factory(true),
///         argless_as_factory(|| 4i == 8),
///     ]);
///
///     // Once we are ready to use the factory, we can call `new_factory` to
///     // convert all dynamic stuff to statically constructed call hierarchy:
///     let anyed_bool_array_factory = container.new_factory();
///
///     // Of course, that returns it anyed (`Box<Any>`), but we can easily get un-anyed version
///     // by downcasting to `Factory<Vec<bool>>` or using a convenience extension
///     // method for that:
///     let bool_array_factory = anyed_bool_array_factory
///         .as_factory_of::<Vec<bool>>().unwrap();
///
///     // Calling it should produce expected boolean vector:
///     assert_eq!(bool_array_factory.take(), vec![true, true, false]);
///
///     // Of course, factory container itself should be usable as argument
///     // for other factories:
///     let metafactory_all_true = metafactory(|values: Vec<bool>| {
///         values.iter().fold(true, |a, &i| a & i)
///     });
///
///     // We can pass it when constructing a factory for this lambda metafactory:
///     let factory_all_true = metafactory_all_true.new(vec![
///         box bool_array_factory.clone() as Box<Any>
///     ])
///         .ok().unwrap() // check for errors here
///         .as_factory_of::<bool>().unwrap() // same story with downcasting
///     ;
///
///     assert_eq!(factory_all_true.take(), false); // not all values are true
/// }
/// ```
pub struct FactoryContainer<'a> {
    any_getter: Box<Any>,
    do_push_items: |&mut Box<Any>, Vec<Box<Any>>|:'a -> (),
    do_new_factory: |&mut Box<Any>|:'a -> Box<Any>, // Don't worry, it's like Javascript ;)
}

impl<'a> FactoryContainer<'a> {
    /// Create new factory container instance for specified type.
    pub fn new<T: 'static>() -> FactoryContainer<'a> {
        FactoryContainer {
            any_getter: box FactoryVecGetter::<T>::new(),
            do_push_items: |any_getter, items| {
                let getter: &mut FactoryVecGetter<T> = any_getter
                    .downcast_mut::<FactoryVecGetter<T>>().unwrap();

                let len = items.len();
                let items_iter = items.into_iter()
                    .map(|i| *i.downcast::<Factory<T>>().ok().unwrap());

                getter.factories.reserve_exact(len);
                getter.factories.extend(items_iter);
            },
            do_new_factory: |any_getter| {
                let getter: &mut FactoryVecGetter<T> = any_getter
                    .downcast_mut::<FactoryVecGetter<T>>().unwrap();

                box Factory::<Vec<T>>::new(getter.boxed_clone())
            }
        }
    }

    /// Push factory items into container.
    ///
    /// Note that all items should already match container type:
    /// if container was created for `int`, all pushed factories should
    /// produce int. Otherwise this method will panic your app.
    pub fn push_items(&mut self, items: Vec<Box<Any>>) {
        (self.do_push_items)(&mut self.any_getter, items);
    }

    /// Produces factory usable as argument for other factories.
    ///
    /// If inner factories make `int` values, this method will make factory
    /// that makes `Vec<int>` values.
    pub fn new_factory(&mut self) -> Box<Any> {
        (self.do_new_factory)(&mut self.any_getter)
    }

    /// Returns factory type `Vec<T>`.
    ///
    /// ```
    /// use di::factory_container::FactoryContainer;
    ///
    /// assert!(FactoryContainer::type_for::<bool>().is::<Vec<bool>>());
    /// ```
    pub fn type_for<T: 'static>() -> TypeDef {
        TypeDef::of::<Vec<T>>()
    }
}

struct FactoryVecGetter<T: 'static> {
    factories: Vec<Factory<T>>,
}

impl<T> Clone for FactoryVecGetter<T> {
    fn clone(&self) -> FactoryVecGetter<T> {
        FactoryVecGetter::<T> {
            factories: self.factories.clone()
        }
    }
}

impl<T> FactoryVecGetter<T> {
    pub fn new() -> FactoryVecGetter<T> {
        FactoryVecGetter::<T> {
            factories: Vec::with_capacity(0)
        }
    }
}

impl<T> Getter<Vec<T>> for FactoryVecGetter<T> {
    fn take(&self) -> Vec<T> {
        // Reserve exact result size.
        let mut items = Vec::<T>::with_capacity(self.factories.len());

        // Construct results from factory results.
        items.extend(
            self.factories.iter()
                .map(|f| f.take())
        );

        // I love Rust.
        items
    }

    fn boxed_clone(&self) -> Box<Getter<Vec<T>> + 'static> {
        box self.clone()
    }
}

#[cfg(test)]
mod test {
    use metafactory::{ argless_as_factory, metafactory, AsFactoryExt };
    use super::{ FactoryContainer };

    #[test]
    fn should_be_usable_as_vec_of_types() {
        let mut container = FactoryContainer::new::<int>();
        container.push_items(vec![
            argless_as_factory(5i),
            argless_as_factory(13i)
        ]);

        let parent_metafactory = metafactory(
            |items: Vec<int>|
                items.into_iter()
                    .map(|i| format!("{}", i))
                    .collect::<Vec<String>>()
                    .connect(", ")
        );

        let parent_getter = parent_metafactory
            .new(vec![
                container.new_factory()
            ]).ok().unwrap()
            .as_factory_of::<String>().unwrap()
        ;

        assert_eq!(parent_getter.take(), "5, 13");
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::rc::*;
use std::cell::*;

use super::super::util::clonecell::*;
use super::super::tree::*;

use super::component::*;

struct Subscription<TData: Clone> {
    callback: RefCell<SubscriptionCallback>,
    data: TData
}

type SubscriptionRef<TData> = Rc<Subscription<TData>>;

///
/// SubscriptionCallback gets around an issue with RefCell.
///
/// If we do RefCell<Box<Fn>> we can't do .borrow_mut()() because the borrow checker treats the box as immutable
/// for reasons that seem counter-intuitive.
///
struct SubscriptionCallback {
    callback: ConsumerCallback
}

impl SubscriptionCallback {
    #[inline]
    fn run_callback(&mut self, change: &TreeChange) {
        let ref mut callback = self.callback;
        callback(change);
    }
}

///
/// The subscription manager is an interior mutable type that can store subscriptions created from consumers.
/// The principle use case is to make it so that publishers and consumers can share a list of subscriptions.
///
pub struct SubscriptionManager<TData: Clone> {
    subscriptions: CloneCell<Vec<SubscriptionRef<TData>>>
}

impl<TData: Clone> SubscriptionManager<TData> {
    ///
    /// Creates a new subscription manager
    ///
    pub fn new() -> SubscriptionManager<TData> {
        SubscriptionManager { subscriptions: CloneCell::new(vec![]) }
    }

    ///
    /// Modifies this subscription manager to add the specified subscription
    ///
    pub fn add_subscription(&self, callback_data: TData, callback: ConsumerCallback) {
        // Turn the callback into a reference
        let new_callback = Rc::new(Subscription { callback: RefCell::new(SubscriptionCallback { callback: callback }), data: callback_data });

        // Retrieve and update the subscriptions
        let mut subscriptions = self.subscriptions.get();
        subscriptions.push(new_callback);
        self.subscriptions.set(subscriptions);
    }

    ///
    /// Calls the subscriptions matching a particular filter
    ///
    pub fn call_subscriptions(&self, call_filter: &Fn(&TData) -> bool, change: &TreeChange) {
        // Retrieve the active subscriptions
        let subscriptions = self.subscriptions.get();

        // Call any subscription matching the filter
        for possible_subscription in subscriptions {
            if call_filter(&possible_subscription.data) {
                let mut callback = possible_subscription.callback.borrow_mut();
                callback.run_callback(change);
            }
        }
    }
}

#[cfg(test)]
mod subscriptionmanager_tests {
    use std::rc::*;
    use std::cell::*;

    use super::*;
    use super::super::super::tree::*;

    #[test]
    pub fn can_call_subscription() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 1);
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
    }

    #[test]
    pub fn can_filter_all_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
    }

    #[test]
    pub fn can_filter_some_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();
        let callback_count2 = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));
        manager.add_subscription(1, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count2.get();
            let new_value   = count_value + 1;
            callback_count2.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|data| { *data == 1 }, &a_change);
        assert!(change_count.get() == 3);
    }
}
<commit_msg>One problem with using FnMut for subscriptions is that feedback can't be done by re-entering a function (which means the immediate_publisher is only suitable for chaining things, not creating feedback loops)<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::rc::*;
use std::cell::*;

use super::super::util::clonecell::*;
use super::super::tree::*;

use super::component::*;

struct Subscription<TData: Clone> {
    callback: RefCell<SubscriptionCallback>,
    data: TData
}

type SubscriptionRef<TData> = Rc<Subscription<TData>>;

///
/// SubscriptionCallback gets around an issue with RefCell.
///
/// If we do RefCell<Box<Fn>> we can't do .borrow_mut()() because the borrow checker treats the box as immutable
/// for reasons that seem counter-intuitive.
///
struct SubscriptionCallback {
    callback: ConsumerCallback
}

impl SubscriptionCallback {
    #[inline]
    fn run_callback(&mut self, change: &TreeChange) {
        let ref mut callback = self.callback;
        callback(change);
    }
}

///
/// The subscription manager is an interior mutable type that can store subscriptions created from consumers.
/// The principle use case is to make it so that publishers and consumers can share a list of subscriptions.
///
pub struct SubscriptionManager<TData: Clone> {
    subscriptions: CloneCell<Vec<SubscriptionRef<TData>>>
}

impl<TData: Clone> SubscriptionManager<TData> {
    ///
    /// Creates a new subscription manager
    ///
    pub fn new() -> SubscriptionManager<TData> {
        SubscriptionManager { subscriptions: CloneCell::new(vec![]) }
    }

    ///
    /// Modifies this subscription manager to add the specified subscription
    ///
    pub fn add_subscription(&self, callback_data: TData, callback: ConsumerCallback) {
        // Turn the callback into a reference
        let new_callback = Rc::new(Subscription { callback: RefCell::new(SubscriptionCallback { callback: callback }), data: callback_data });

        // Retrieve and update the subscriptions
        let mut subscriptions = self.subscriptions.get();
        subscriptions.push(new_callback);
        self.subscriptions.set(subscriptions);
    }

    ///
    /// Calls the subscriptions matching a particular filter
    ///
    pub fn call_subscriptions(&self, call_filter: &Fn(&TData) -> bool, change: &TreeChange) {
        // Retrieve the active subscriptions
        let subscriptions = self.subscriptions.get();

        // Call any subscription matching the filter
        for possible_subscription in subscriptions {
            if call_filter(&possible_subscription.data) {
                // Caution: this will fail at runtime with a borrowing error if this function is re-entered (ie, if there is a feedback loop)
                let mut callback = possible_subscription.callback.borrow_mut();
                callback.run_callback(change);
            }
        }
    }
}

#[cfg(test)]
mod subscriptionmanager_tests {
    use std::rc::*;
    use std::cell::*;

    use super::*;
    use super::super::super::tree::*;

    #[test]
    pub fn can_call_subscription() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 1);
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
    }

    #[test]
    pub fn can_filter_all_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 0);
    }

    #[test]
    pub fn can_filter_some_subscriptions() {
        // Create a subscription manager and a sample change (doesn't matter what the change is)
        let manager         = SubscriptionManager::<i32>::new();
        let a_change        = TreeChange::new(&TreeAddress::Here, TreeChangeType::Child, Some(&"".to_tree_node()));

        // Store the change count in a shared cell
        let change_count    = Rc::new(Cell::<i32>::new(0));
        let callback_count  = change_count.clone();
        let callback_count2 = change_count.clone();

        // Must initially be 0
        assert!(change_count.get() == 0);

        // Create a subscription that updates the change count
        manager.add_subscription(0, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count.get();
            let new_value   = count_value + 1;
            callback_count.set(new_value);
        }));
        manager.add_subscription(1, Box::new(move |_change: &TreeChange| {
            let count_value = callback_count2.get();
            let new_value   = count_value + 1;
            callback_count2.set(new_value);
        }));

        // Call the subscription a few times (result should not update)
        manager.call_subscriptions(&|_data| { true }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|_data| { false }, &a_change);
        assert!(change_count.get() == 2);
        manager.call_subscriptions(&|data| { *data == 1 }, &a_change);
        assert!(change_count.get() == 3);
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::f64;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::filter::Filter;
use crate::node::RsvgNode;
use crate::paint_server::PaintServer;
use crate::properties::ComputedValues;
use crate::rect::IRect;
use crate::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use crate::unit_interval::UnitInterval;

use super::error::FilterError;
use super::input::{CustomIdent, Input};

/// A filter primitive output.
#[derive(Debug, Clone)]
pub struct FilterOutput {
    /// The surface after the filter primitive was applied.
    pub surface: SharedImageSurface,

    /// The filter primitive subregion.
    pub bounds: IRect,
}

/// A filter primitive result.
#[derive(Debug, Clone)]
pub struct FilterResult {
    /// The name of this result: the value of the `result` attribute.
    pub name: Option<CustomIdent>,

    /// The output.
    pub output: FilterOutput,
}

/// An input to a filter primitive.
#[derive(Debug, Clone)]
pub enum FilterInput {
    /// One of the standard inputs.
    StandardInput(SharedImageSurface),
    /// Output of another filter primitive.
    PrimitiveOutput(FilterOutput),
}

/// The filter rendering context.
pub struct FilterContext {
    /// The <filter> node.
    node: RsvgNode,
    /// Bounding box of node being filtered
    node_bbox: BoundingBox,
    /// Values from the node which referenced this filter.
    computed_from_node_being_filtered: ComputedValues,
    /// The source graphic surface.
    source_surface: SharedImageSurface,
    /// Output of the last filter primitive.
    last_result: Option<FilterOutput>,
    /// Surfaces of the previous filter primitives by name.
    previous_results: HashMap<CustomIdent, FilterOutput>,
    /// The background surface. Computed lazily.
    background_surface: RefCell<Option<Result<SharedImageSurface, FilterError>>>,
    /// The filter effects region.
    effects_region: BoundingBox,
    /// Whether the currently rendered filter primitive uses linear RGB for color operations.
    ///
    /// This affects `get_input()` and `store_result()` which should perform linearization and
    /// unlinearization respectively when this is set to `true`.
    processing_linear_rgb: bool,

    /// The filter element affine matrix.
    ///
    /// If `filterUnits == userSpaceOnUse`, equal to the drawing context matrix, so, for example,
    /// if the target node is in a group with `transform="translate(30, 20)"`, this will be equal
    /// to a matrix that translates to 30, 20 (and does not scale). Note that the target node
    /// bounding box isn't included in the computations in this case.
    ///
    /// If `filterUnits == objectBoundingBox`, equal to the target node bounding box matrix
    /// multiplied by the drawing context matrix, so, for example, if the target node is in a group
    /// with `transform="translate(30, 20)"` and also has `x="1", y="1", width="50", height="50"`,
    /// this will be equal to a matrix that translates to 31, 21 and scales to 50, 50.
    ///
    /// This is to be used in conjunction with setting the viewbox size to account for the scaling.
    /// For `filterUnits == userSpaceOnUse`, the viewbox will have the actual resolution size, and
    /// for `filterUnits == objectBoundingBox`, the viewbox will have the size of 1, 1.
    _affine: cairo::Matrix,

    /// The filter primitive affine matrix.
    ///
    /// See the comments for `_affine`, they largely apply here.
    paffine: cairo::Matrix,
}

impl FilterContext {
    /// Creates a new `FilterContext`.
    pub fn new(
        filter_node: &RsvgNode,
        computed_from_node_being_filtered: &ComputedValues,
        source_surface: SharedImageSurface,
        draw_ctx: &mut DrawingCtx,
        node_bbox: BoundingBox,
    ) -> Self {
        let cr_affine = draw_ctx.get_cairo_context().get_matrix();

        // The rect can be empty (for example, if the filter is applied to an empty group).
        // However, with userSpaceOnUse it's still possible to create images with a filter.
        let bbox_rect = node_bbox.rect.unwrap_or_default();

        let node_data = filter_node.borrow();
        let filter = node_data.get_impl::<Filter>();

        let affine = match filter.get_filter_units() {
            CoordUnits::UserSpaceOnUse => cr_affine,
            CoordUnits::ObjectBoundingBox => {
                let affine = cairo::Matrix::new(
                    bbox_rect.width(),
                    0.0,
                    0.0,
                    bbox_rect.height(),
                    bbox_rect.x0,
                    bbox_rect.y0,
                );
                cairo::Matrix::multiply(&affine, &cr_affine)
            }
        };

        let paffine = match filter.get_primitive_units() {
            CoordUnits::UserSpaceOnUse => cr_affine,
            CoordUnits::ObjectBoundingBox => {
                let affine = cairo::Matrix::new(
                    bbox_rect.width(),
                    0.0,
                    0.0,
                    bbox_rect.height(),
                    bbox_rect.x0,
                    bbox_rect.y0,
                );
                cairo::Matrix::multiply(&affine, &cr_affine)
            }
        };

        let width = source_surface.width();
        let height = source_surface.height();

        Self {
            node: filter_node.clone(),
            node_bbox,
            computed_from_node_being_filtered: computed_from_node_being_filtered.clone(),
            source_surface,
            last_result: None,
            previous_results: HashMap::new(),
            background_surface: RefCell::new(None),
            effects_region: filter.compute_effects_region(
                computed_from_node_being_filtered,
                draw_ctx,
                affine,
                f64::from(width),
                f64::from(height),
            ),
            processing_linear_rgb: false,
            _affine: affine,
            paffine,
        }
    }

    /// Returns the computed values from the node that referenced this filter.
    #[inline]
    pub fn get_computed_values_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Returns the surface corresponding to the source graphic.
    #[inline]
    pub fn source_graphic(&self) -> &SharedImageSurface {
        &self.source_surface
    }

    /// Returns the surface corresponding to the background image snapshot.
    pub fn background_image(
        &self,
        draw_ctx: &DrawingCtx,
    ) -> Result<SharedImageSurface, FilterError> {
        {
            // At this point either no, or only immutable references to background_surface exist, so
            // it's ok to make an immutable reference.
            let bg = self.background_surface.borrow();

            // If background_surface was already computed, return the immutable reference. It will
            // get bound to the &self lifetime by the function return type.
            if let Some(ref result) = *bg {
                return result.clone();
            }
        }

        // If we got here, then background_surface hasn't been computed yet. This means there are
        // no references to it and we can create a mutable reference.
        let mut bg = self.background_surface.borrow_mut();

        *bg = Some(
            draw_ctx
                .get_snapshot(self.source_surface.width(), self.source_surface.height())
                .map_err(FilterError::CairoError),
        );

        // Return the only existing reference as immutable.
        bg.as_ref()
            .unwrap()
            .as_ref()
            .map(|surf| surf.clone())
            .map_err(|&s| s)
    }

    /// Converts this `FilterContext` into the surface corresponding to the output of the filter
    /// chain.
    ///
    /// The returned surface is in the sRGB color space.
    // TODO: sRGB conversion should probably be done by the caller.
    #[inline]
    pub fn into_output(self) -> Result<SharedImageSurface, cairo::Status> {
        match self.last_result {
            Some(FilterOutput { surface, bounds }) => surface.to_srgb(bounds),
            None => SharedImageSurface::empty(
                self.source_surface.width(),
                self.source_surface.height(),
                SurfaceType::AlphaOnly,
            ),
        }
    }

    /// Stores a filter primitive result into the context.
    #[inline]
    pub fn store_result(&mut self, result: FilterResult) -> Result<(), FilterError> {
        if let Some(name) = result.name {
            self.previous_results.insert(name, result.output.clone());
        }

        self.last_result = Some(result.output);
        Ok(())
    }

    /// Returns the paffine matrix.
    #[inline]
    pub fn paffine(&self) -> cairo::Matrix {
        self.paffine
    }

    /// Returns the filter effects region.
    #[inline]
    pub fn effects_region(&self) -> BoundingBox {
        self.effects_region
    }

    pub fn get_computed_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Pushes the viewport size based on the value of `primitiveUnits`.
    pub fn get_view_params(&self, draw_ctx: &mut DrawingCtx) -> ViewParams {
        let node_data = self.node.borrow();
        let filter = node_data.get_impl::<Filter>();

        // See comments in compute_effects_region() for how this works.
        if filter.get_primitive_units() == CoordUnits::ObjectBoundingBox {
            draw_ctx.push_view_box(1.0, 1.0)
        } else {
            draw_ctx.get_view_params()
        }
    }

    /// Computes and returns a surface corresponding to the given paint server.
    fn get_paint_server_surface(
        &self,
        draw_ctx: &mut DrawingCtx,
        paint_server: &PaintServer,
        opacity: UnitInterval,
    ) -> Result<cairo::ImageSurface, cairo::Status> {
        let surface = cairo::ImageSurface::create(
            cairo::Format::ARgb32,
            self.source_surface.width(),
            self.source_surface.height(),
        )?;

        let cr_save = draw_ctx.get_cairo_context();
        let cr = cairo::Context::new(&surface);
        draw_ctx.set_cairo_context(&cr);

        // FIXME: we are ignoring the following error; propagate it upstream
        let _ = draw_ctx
            .set_source_paint_server(
                paint_server,
                opacity,
                &self.node_bbox,
                self.computed_from_node_being_filtered.color.0,
            )
            .and_then(|had_paint_server| {
                if had_paint_server {
                    cr.paint();
                }
                Ok(())
            });

        draw_ctx.set_cairo_context(&cr_save);
        Ok(surface)
    }

    /// Retrieves the filter input surface according to the SVG rules.
    ///
    /// Does not take `processing_linear_rgb` into account.
    fn get_input_raw(
        &self,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        if in_.is_none() {
            // No value => use the last result.
            // As per the SVG spec, if the filter primitive is the first in the chain, return the
            // source graphic.
            if let Some(output) = self.last_result.as_ref() {
                return Ok(FilterInput::PrimitiveOutput(output.clone()));
            } else {
                return Ok(FilterInput::StandardInput(self.source_graphic().clone()));
            }
        }

        let values = &self.computed_from_node_being_filtered;

        match *in_.unwrap() {
            Input::SourceGraphic => Ok(FilterInput::StandardInput(self.source_graphic().clone())),

            Input::SourceAlpha => self
                .source_graphic()
                .extract_alpha(self.effects_region().rect.unwrap().into())
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::BackgroundImage => self
                .background_image(draw_ctx)
                .map(FilterInput::StandardInput),

            Input::BackgroundAlpha => self
                .background_image(draw_ctx)
                .and_then(|surface| {
                    surface
                        .extract_alpha(self.effects_region().rect.unwrap().into())
                        .map_err(FilterError::CairoError)
                })
                .map(FilterInput::StandardInput),

            Input::FillPaint => self
                .get_paint_server_surface(draw_ctx, &values.fill.0, values.fill_opacity.0)
                .map_err(FilterError::CairoError)
                .and_then(|surface| {
                    SharedImageSurface::wrap(surface, SurfaceType::SRgb)
                        .map_err(FilterError::CairoError)
                })
                .map(FilterInput::StandardInput),

            Input::StrokePaint => self
                .get_paint_server_surface(draw_ctx, &values.stroke.0, values.stroke_opacity.0)
                .map_err(FilterError::CairoError)
                .and_then(|surface| {
                    SharedImageSurface::wrap(surface, SurfaceType::SRgb)
                        .map_err(FilterError::CairoError)
                })
                .map(FilterInput::StandardInput),

            Input::FilterOutput(ref name) => self
                .previous_results
                .get(name)
                .cloned()
                .map(FilterInput::PrimitiveOutput)
                .ok_or(FilterError::InvalidInput),
        }
    }

    /// Retrieves the filter input surface according to the SVG rules.
    pub fn get_input(
        &self,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        let raw = self.get_input_raw(draw_ctx, in_)?;

        // Convert the input surface to the desired format.
        let (surface, bounds) = match raw {
            FilterInput::StandardInput(ref surface) => {
                (surface, self.effects_region().rect.unwrap().into())
            }
            FilterInput::PrimitiveOutput(FilterOutput {
                ref surface,
                ref bounds,
            }) => (surface, *bounds),
        };

        let surface = if self.processing_linear_rgb {
            surface.to_linear_rgb(bounds)
        } else {
            surface.to_srgb(bounds)
        };
        surface
            .map_err(FilterError::CairoError)
            .map(|surface| match raw {
                FilterInput::StandardInput(_) => FilterInput::StandardInput(surface),
                FilterInput::PrimitiveOutput(ref output) => {
                    FilterInput::PrimitiveOutput(FilterOutput { surface, ..*output })
                }
            })
    }

    /// Calls the given closure with linear RGB processing enabled.
    #[inline]
    pub fn with_linear_rgb<T, F: FnOnce(&mut FilterContext) -> T>(&mut self, f: F) -> T {
        self.processing_linear_rgb = true;
        let rv = f(self);
        self.processing_linear_rgb = false;
        rv
    }

    /// Applies the `primitiveUnits` coordinate transformation to a non-x or y distance.
    #[inline]
    pub fn transform_dist(&self, d: f64) -> f64 {
        d * (self.paffine.xx.powi(2) + self.paffine.yy.powi(2)).sqrt() / f64::consts::SQRT_2
    }
}

impl FilterInput {
    /// Retrieves the surface from `FilterInput`.
    #[inline]
    pub fn surface(&self) -> &SharedImageSurface {
        match *self {
            FilterInput::StandardInput(ref surface) => surface,
            FilterInput::PrimitiveOutput(FilterOutput { ref surface, .. }) => surface,
        }
    }
}
<commit_msg>filters: port context to ExclusiveImageSurface<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::f64;

use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::filter::Filter;
use crate::node::RsvgNode;
use crate::paint_server::PaintServer;
use crate::properties::ComputedValues;
use crate::rect::IRect;
use crate::surface_utils::shared_surface::{
    ExclusiveImageSurface, SharedImageSurface, SurfaceType,
};
use crate::unit_interval::UnitInterval;

use super::error::FilterError;
use super::input::{CustomIdent, Input};

/// A filter primitive output.
#[derive(Debug, Clone)]
pub struct FilterOutput {
    /// The surface after the filter primitive was applied.
    pub surface: SharedImageSurface,

    /// The filter primitive subregion.
    pub bounds: IRect,
}

/// A filter primitive result.
#[derive(Debug, Clone)]
pub struct FilterResult {
    /// The name of this result: the value of the `result` attribute.
    pub name: Option<CustomIdent>,

    /// The output.
    pub output: FilterOutput,
}

/// An input to a filter primitive.
#[derive(Debug, Clone)]
pub enum FilterInput {
    /// One of the standard inputs.
    StandardInput(SharedImageSurface),
    /// Output of another filter primitive.
    PrimitiveOutput(FilterOutput),
}

/// The filter rendering context.
pub struct FilterContext {
    /// The <filter> node.
    node: RsvgNode,
    /// Bounding box of node being filtered
    node_bbox: BoundingBox,
    /// Values from the node which referenced this filter.
    computed_from_node_being_filtered: ComputedValues,
    /// The source graphic surface.
    source_surface: SharedImageSurface,
    /// Output of the last filter primitive.
    last_result: Option<FilterOutput>,
    /// Surfaces of the previous filter primitives by name.
    previous_results: HashMap<CustomIdent, FilterOutput>,
    /// The background surface. Computed lazily.
    background_surface: RefCell<Option<Result<SharedImageSurface, FilterError>>>,
    /// The filter effects region.
    effects_region: BoundingBox,
    /// Whether the currently rendered filter primitive uses linear RGB for color operations.
    ///
    /// This affects `get_input()` and `store_result()` which should perform linearization and
    /// unlinearization respectively when this is set to `true`.
    processing_linear_rgb: bool,

    /// The filter element affine matrix.
    ///
    /// If `filterUnits == userSpaceOnUse`, equal to the drawing context matrix, so, for example,
    /// if the target node is in a group with `transform="translate(30, 20)"`, this will be equal
    /// to a matrix that translates to 30, 20 (and does not scale). Note that the target node
    /// bounding box isn't included in the computations in this case.
    ///
    /// If `filterUnits == objectBoundingBox`, equal to the target node bounding box matrix
    /// multiplied by the drawing context matrix, so, for example, if the target node is in a group
    /// with `transform="translate(30, 20)"` and also has `x="1", y="1", width="50", height="50"`,
    /// this will be equal to a matrix that translates to 31, 21 and scales to 50, 50.
    ///
    /// This is to be used in conjunction with setting the viewbox size to account for the scaling.
    /// For `filterUnits == userSpaceOnUse`, the viewbox will have the actual resolution size, and
    /// for `filterUnits == objectBoundingBox`, the viewbox will have the size of 1, 1.
    _affine: cairo::Matrix,

    /// The filter primitive affine matrix.
    ///
    /// See the comments for `_affine`, they largely apply here.
    paffine: cairo::Matrix,
}

impl FilterContext {
    /// Creates a new `FilterContext`.
    pub fn new(
        filter_node: &RsvgNode,
        computed_from_node_being_filtered: &ComputedValues,
        source_surface: SharedImageSurface,
        draw_ctx: &mut DrawingCtx,
        node_bbox: BoundingBox,
    ) -> Self {
        let cr_affine = draw_ctx.get_cairo_context().get_matrix();

        // The rect can be empty (for example, if the filter is applied to an empty group).
        // However, with userSpaceOnUse it's still possible to create images with a filter.
        let bbox_rect = node_bbox.rect.unwrap_or_default();

        let node_data = filter_node.borrow();
        let filter = node_data.get_impl::<Filter>();

        let affine = match filter.get_filter_units() {
            CoordUnits::UserSpaceOnUse => cr_affine,
            CoordUnits::ObjectBoundingBox => {
                let affine = cairo::Matrix::new(
                    bbox_rect.width(),
                    0.0,
                    0.0,
                    bbox_rect.height(),
                    bbox_rect.x0,
                    bbox_rect.y0,
                );
                cairo::Matrix::multiply(&affine, &cr_affine)
            }
        };

        let paffine = match filter.get_primitive_units() {
            CoordUnits::UserSpaceOnUse => cr_affine,
            CoordUnits::ObjectBoundingBox => {
                let affine = cairo::Matrix::new(
                    bbox_rect.width(),
                    0.0,
                    0.0,
                    bbox_rect.height(),
                    bbox_rect.x0,
                    bbox_rect.y0,
                );
                cairo::Matrix::multiply(&affine, &cr_affine)
            }
        };

        let width = source_surface.width();
        let height = source_surface.height();

        Self {
            node: filter_node.clone(),
            node_bbox,
            computed_from_node_being_filtered: computed_from_node_being_filtered.clone(),
            source_surface,
            last_result: None,
            previous_results: HashMap::new(),
            background_surface: RefCell::new(None),
            effects_region: filter.compute_effects_region(
                computed_from_node_being_filtered,
                draw_ctx,
                affine,
                f64::from(width),
                f64::from(height),
            ),
            processing_linear_rgb: false,
            _affine: affine,
            paffine,
        }
    }

    /// Returns the computed values from the node that referenced this filter.
    #[inline]
    pub fn get_computed_values_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Returns the surface corresponding to the source graphic.
    #[inline]
    pub fn source_graphic(&self) -> &SharedImageSurface {
        &self.source_surface
    }

    /// Returns the surface corresponding to the background image snapshot.
    pub fn background_image(
        &self,
        draw_ctx: &DrawingCtx,
    ) -> Result<SharedImageSurface, FilterError> {
        {
            // At this point either no, or only immutable references to background_surface exist, so
            // it's ok to make an immutable reference.
            let bg = self.background_surface.borrow();

            // If background_surface was already computed, return the immutable reference. It will
            // get bound to the &self lifetime by the function return type.
            if let Some(ref result) = *bg {
                return result.clone();
            }
        }

        // If we got here, then background_surface hasn't been computed yet. This means there are
        // no references to it and we can create a mutable reference.
        let mut bg = self.background_surface.borrow_mut();

        *bg = Some(
            draw_ctx
                .get_snapshot(self.source_surface.width(), self.source_surface.height())
                .map_err(FilterError::CairoError),
        );

        // Return the only existing reference as immutable.
        bg.as_ref()
            .unwrap()
            .as_ref()
            .map(|surf| surf.clone())
            .map_err(|&s| s)
    }

    /// Converts this `FilterContext` into the surface corresponding to the output of the filter
    /// chain.
    ///
    /// The returned surface is in the sRGB color space.
    // TODO: sRGB conversion should probably be done by the caller.
    #[inline]
    pub fn into_output(self) -> Result<SharedImageSurface, cairo::Status> {
        match self.last_result {
            Some(FilterOutput { surface, bounds }) => surface.to_srgb(bounds),
            None => SharedImageSurface::empty(
                self.source_surface.width(),
                self.source_surface.height(),
                SurfaceType::AlphaOnly,
            ),
        }
    }

    /// Stores a filter primitive result into the context.
    #[inline]
    pub fn store_result(&mut self, result: FilterResult) -> Result<(), FilterError> {
        if let Some(name) = result.name {
            self.previous_results.insert(name, result.output.clone());
        }

        self.last_result = Some(result.output);
        Ok(())
    }

    /// Returns the paffine matrix.
    #[inline]
    pub fn paffine(&self) -> cairo::Matrix {
        self.paffine
    }

    /// Returns the filter effects region.
    #[inline]
    pub fn effects_region(&self) -> BoundingBox {
        self.effects_region
    }

    pub fn get_computed_from_node_being_filtered(&self) -> &ComputedValues {
        &self.computed_from_node_being_filtered
    }

    /// Pushes the viewport size based on the value of `primitiveUnits`.
    pub fn get_view_params(&self, draw_ctx: &mut DrawingCtx) -> ViewParams {
        let node_data = self.node.borrow();
        let filter = node_data.get_impl::<Filter>();

        // See comments in compute_effects_region() for how this works.
        if filter.get_primitive_units() == CoordUnits::ObjectBoundingBox {
            draw_ctx.push_view_box(1.0, 1.0)
        } else {
            draw_ctx.get_view_params()
        }
    }

    /// Computes and returns a surface corresponding to the given paint server.
    fn get_paint_server_surface(
        &self,
        draw_ctx: &mut DrawingCtx,
        paint_server: &PaintServer,
        opacity: UnitInterval,
    ) -> Result<SharedImageSurface, cairo::Status> {
        let mut surface = ExclusiveImageSurface::new(
            self.source_surface.width(),
            self.source_surface.height(),
            SurfaceType::SRgb,
        )?;

        surface.draw(&mut |cr| {
            let cr_save = draw_ctx.get_cairo_context();
            draw_ctx.set_cairo_context(&cr);

            // FIXME: we are ignoring the following error; propagate it upstream
            let _ = draw_ctx
                .set_source_paint_server(
                    paint_server,
                    opacity,
                    &self.node_bbox,
                    self.computed_from_node_being_filtered.color.0,
                )
                .and_then(|had_paint_server| {
                    if had_paint_server {
                        cr.paint();
                    }
                    Ok(())
                });

            draw_ctx.set_cairo_context(&cr_save);

            Ok(())
        })?;

        surface.share()
    }

    /// Retrieves the filter input surface according to the SVG rules.
    ///
    /// Does not take `processing_linear_rgb` into account.
    fn get_input_raw(
        &self,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        if in_.is_none() {
            // No value => use the last result.
            // As per the SVG spec, if the filter primitive is the first in the chain, return the
            // source graphic.
            if let Some(output) = self.last_result.as_ref() {
                return Ok(FilterInput::PrimitiveOutput(output.clone()));
            } else {
                return Ok(FilterInput::StandardInput(self.source_graphic().clone()));
            }
        }

        let values = &self.computed_from_node_being_filtered;

        match *in_.unwrap() {
            Input::SourceGraphic => Ok(FilterInput::StandardInput(self.source_graphic().clone())),

            Input::SourceAlpha => self
                .source_graphic()
                .extract_alpha(self.effects_region().rect.unwrap().into())
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::BackgroundImage => self
                .background_image(draw_ctx)
                .map(FilterInput::StandardInput),

            Input::BackgroundAlpha => self
                .background_image(draw_ctx)
                .and_then(|surface| {
                    surface
                        .extract_alpha(self.effects_region().rect.unwrap().into())
                        .map_err(FilterError::CairoError)
                })
                .map(FilterInput::StandardInput),

            Input::FillPaint => self
                .get_paint_server_surface(draw_ctx, &values.fill.0, values.fill_opacity.0)
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::StrokePaint => self
                .get_paint_server_surface(draw_ctx, &values.stroke.0, values.stroke_opacity.0)
                .map_err(FilterError::CairoError)
                .map(FilterInput::StandardInput),

            Input::FilterOutput(ref name) => self
                .previous_results
                .get(name)
                .cloned()
                .map(FilterInput::PrimitiveOutput)
                .ok_or(FilterError::InvalidInput),
        }
    }

    /// Retrieves the filter input surface according to the SVG rules.
    pub fn get_input(
        &self,
        draw_ctx: &mut DrawingCtx,
        in_: Option<&Input>,
    ) -> Result<FilterInput, FilterError> {
        let raw = self.get_input_raw(draw_ctx, in_)?;

        // Convert the input surface to the desired format.
        let (surface, bounds) = match raw {
            FilterInput::StandardInput(ref surface) => {
                (surface, self.effects_region().rect.unwrap().into())
            }
            FilterInput::PrimitiveOutput(FilterOutput {
                ref surface,
                ref bounds,
            }) => (surface, *bounds),
        };

        let surface = if self.processing_linear_rgb {
            surface.to_linear_rgb(bounds)
        } else {
            surface.to_srgb(bounds)
        };
        surface
            .map_err(FilterError::CairoError)
            .map(|surface| match raw {
                FilterInput::StandardInput(_) => FilterInput::StandardInput(surface),
                FilterInput::PrimitiveOutput(ref output) => {
                    FilterInput::PrimitiveOutput(FilterOutput { surface, ..*output })
                }
            })
    }

    /// Calls the given closure with linear RGB processing enabled.
    #[inline]
    pub fn with_linear_rgb<T, F: FnOnce(&mut FilterContext) -> T>(&mut self, f: F) -> T {
        self.processing_linear_rgb = true;
        let rv = f(self);
        self.processing_linear_rgb = false;
        rv
    }

    /// Applies the `primitiveUnits` coordinate transformation to a non-x or y distance.
    #[inline]
    pub fn transform_dist(&self, d: f64) -> f64 {
        d * (self.paffine.xx.powi(2) + self.paffine.yy.powi(2)).sqrt() / f64::consts::SQRT_2
    }
}

impl FilterInput {
    /// Retrieves the surface from `FilterInput`.
    #[inline]
    pub fn surface(&self) -> &SharedImageSurface {
        match *self {
            FilterInput::StandardInput(ref surface) => surface,
            FilterInput::PrimitiveOutput(FilterOutput { ref surface, .. }) => surface,
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]

extern crate gl_generator;
extern crate khronos_api;

use std::os;
use std::old_io::File;

mod textures;

fn main() {
    let dest = Path::new(os::getenv("OUT_DIR").unwrap());

    textures::build_texture_file(&mut File::create(&dest.join("textures.rs")).unwrap());

    let mut gl_bindings = File::create(&dest.join("gl_bindings.rs")).unwrap();
    gl_generator::generate_bindings(gl_generator::StructGenerator,
                                    gl_generator::registry::Ns::Gl,
                                    khronos_api::GL_XML,
                                    vec![
                                        "GL_EXT_direct_state_access".to_string(),
                                        "GL_EXT_framebuffer_object".to_string(),
                                        "GL_EXT_framebuffer_blit".to_string(),
                                        "GL_NVX_gpu_memory_info".to_string(),
                                        "GL_ATI_meminfo".to_string(),
                                        "GL_EXT_texture_filter_anisotropic".to_string(),
                                        "GL_ARB_buffer_storage".to_string(),
                                        "GL_APPLE_vertex_array_object".to_string(),
                                        "GL_ARB_vertex_buffer_object".to_string(),
                                        "GL_ARB_shader_objects".to_string(),
                                        "GL_ARB_vertex_shader".to_string(),
                                        "GL_ARB_texture_rg".to_string(),
                                        "GL_EXT_texture_integer".to_string(),
                                        "GL_ARB_texture_rgb10_a2ui".to_string(),
                                        "GL_ARB_texture_float".to_string(),
                                        "GL_EXT_packed_depth_stencil".to_string(),
                                        "GL_ARB_debug_output".to_string(),
                                    ],
                                    "4.5", "compatibility", &mut gl_bindings).unwrap();
}
<commit_msg>Generate bindings for OpenGL ES as well<commit_after>#![allow(unstable)]

extern crate gl_generator;
extern crate khronos_api;

use std::os;
use std::old_io::File;
use std::old_io::BufReader;
use gl_generator::generators::Generator;

mod textures;

fn main() {
    let dest = Path::new(os::getenv("OUT_DIR").unwrap());

    textures::build_texture_file(&mut File::create(&dest.join("textures.rs")).unwrap());

    let mut gl_bindings = File::create(&dest.join("gl_bindings.rs")).unwrap();
    generate_gl_bindings(&mut gl_bindings);
}

fn generate_gl_bindings<W>(dest: &mut W) where W: Writer {
    let gl_registry = {
        let reader = BufReader::new(khronos_api::GL_XML);
        let ns = gl_generator::registry::Ns::Gl;

        let filter = gl_generator::registry::Filter {
            api: gl_generator::registry::Ns::Gl.to_string(),
            extensions: vec![
                "GL_EXT_direct_state_access".to_string(),
                "GL_EXT_framebuffer_object".to_string(),
                "GL_EXT_framebuffer_blit".to_string(),
                "GL_NVX_gpu_memory_info".to_string(),
                "GL_ATI_meminfo".to_string(),
                "GL_EXT_texture_filter_anisotropic".to_string(),
                "GL_ARB_buffer_storage".to_string(),
                "GL_APPLE_vertex_array_object".to_string(),
                "GL_ARB_vertex_buffer_object".to_string(),
                "GL_ARB_shader_objects".to_string(),
                "GL_ARB_vertex_shader".to_string(),
                "GL_ARB_texture_rg".to_string(),
                "GL_EXT_texture_integer".to_string(),
                "GL_ARB_texture_rgb10_a2ui".to_string(),
                "GL_ARB_texture_float".to_string(),
                "GL_EXT_packed_depth_stencil".to_string(),
                "GL_ARB_debug_output".to_string(),
            ],
            version: "4.5".to_string(),
            profile: "compatibility".to_string(),
        };

        gl_generator::registry::Registry::from_xml(reader, ns, Some(filter))
    };

    let gles_registry = {
        let reader = BufReader::new(khronos_api::GL_XML);
        let ns = gl_generator::registry::Ns::Gles2;

        let filter = gl_generator::registry::Filter {
            api: gl_generator::registry::Ns::Gles2.to_string(),
            extensions: vec![
                "GL_OES_texture_npot".to_string(),
            ],
            version: "3.1".to_string(),
            profile: "compatibility".to_string(),
        };

        gl_generator::registry::Registry::from_xml(reader, ns, Some(filter))
    };

    gl_generator::StructGenerator.write(&(gl_registry + gles_registry),
                                        gl_generator::registry::Ns::Gl, dest).unwrap();
}
<|endoftext|>


<commit_before>//! Key-Value semantics.

use super::Database;

use options::{WriteOptions,ReadOptions,c_writeoptions,c_readoptions};
use super::error::Error;
use database::key::Key;
use std::ptr;
use std::slice::from_raw_parts;
use libc::{c_char,size_t};
use leveldb_sys::*;

/// Key-Value-Access to the leveldb database, providing
/// a basic interface.
pub trait KV<K: Key> {
    /// get a value from the database.
    ///
    /// The passed key will be compared using the comparator.
    fn get<'a>(&self,
           options: ReadOptions<'a,K>,
           key: K) -> Result<Option<Vec<u8>>, Error>;
    /// put a binary value into the database.
    ///
    /// If the key is already present in the database, it will be overwritten.
    ///
    /// The passed key will be compared using the comparator.
    ///
    /// The database will be synced to disc if `options.sync == true`. This is
    /// NOT the default.
    fn put(&self,
           options: WriteOptions,
           key: K,
           value: &[u8]) -> Result<(), Error>;
    /// delete a value from the database.
    ///
    /// The passed key will be compared using the comparator.
    ///
    /// The database will be synced to disc if `options.sync == true`. This is
    /// NOT the default.
    fn delete(&self,
              options: WriteOptions,
              key: K) -> Result<(), Error>;
}

impl<K: Key> KV<K> for Database<K> {
  /// put a binary value into the database.
  ///
  /// If the key is already present in the database, it will be overwritten.
  ///
  /// The passed key will be compared using the comparator.
  ///
  /// The database will be synced to disc if `options.sync == true`. This is
  /// NOT the default.
  fn put(&self,
             options: WriteOptions,
             key: K,
             value: &[u8]) -> Result<(), Error> {
    unsafe {
      key.as_slice(|k| {
        let mut error = ptr::null_mut();
        let c_writeoptions = c_writeoptions(options);
        leveldb_put(self.database.ptr,
                    c_writeoptions,
                    k.as_ptr() as *mut c_char,
                    k.len() as size_t,
                    value.as_ptr() as *mut c_char,
                    value.len() as size_t,
                    &mut error);
        leveldb_writeoptions_destroy(c_writeoptions);

        if error == ptr::null_mut() {
          Ok(())
        } else {
          Err(Error::new_from_i8(error))
        }
      })
    }
  }

  /// delete a value from the database.
  ///
  /// The passed key will be compared using the comparator.
  ///
  /// The database will be synced to disc if `options.sync == true`. This is
  /// NOT the default.
  fn delete(&self,
                options: WriteOptions,
                key: K) -> Result<(), Error> {
    unsafe {
      key.as_slice(|k| {
        let mut error = ptr::null_mut();
        let c_writeoptions = c_writeoptions(options);
        leveldb_delete(self.database.ptr,
                       c_writeoptions,
                       k.as_ptr() as *mut c_char,
                       k.len() as size_t,
                       &mut error);
        leveldb_writeoptions_destroy(c_writeoptions);
        if error == ptr::null_mut() {
          Ok(())
        } else {
          Err(Error::new_from_i8(error))
        }
      })
    }
  }

  /// get a value from the database.
  ///
  /// The passed key will be compared using the comparator.
  fn get<'a>(&self,
             options: ReadOptions<'a,K>,
             key: K) -> Result<Option<Vec<u8>>, Error> {
    unsafe {
      key.as_slice(|k| {
        let mut error = ptr::null_mut();
        let mut length: size_t = 0;
        let c_readoptions = c_readoptions(&options);
        let result = leveldb_get(self.database.ptr,
                                 c_readoptions,
                                 k.as_ptr() as *mut c_char,
                                 k.len() as size_t,
                                 &mut length,
                                 &mut error);
        leveldb_readoptions_destroy(c_readoptions);

        if error == ptr::null_mut() {
          if result == ptr::null_mut() {
            Ok(None)
          } else {
            let vec = from_raw_parts(result as *mut u8, length as usize).to_vec();
            Ok(Some(vec))
          }
        } else {
          Err(Error::new_from_i8(error))
        }
      })
    }
  }
}
<commit_msg>KV::get(): free result<commit_after>//! Key-Value semantics.

use super::Database;

use options::{WriteOptions,ReadOptions,c_writeoptions,c_readoptions};
use super::error::Error;
use database::key::Key;
use std::ptr;
use std::slice::from_raw_parts;
use libc::{c_char,size_t,c_void};
use leveldb_sys::*;

/// Key-Value-Access to the leveldb database, providing
/// a basic interface.
pub trait KV<K: Key> {
    /// get a value from the database.
    ///
    /// The passed key will be compared using the comparator.
    fn get<'a>(&self,
           options: ReadOptions<'a,K>,
           key: K) -> Result<Option<Vec<u8>>, Error>;
    /// put a binary value into the database.
    ///
    /// If the key is already present in the database, it will be overwritten.
    ///
    /// The passed key will be compared using the comparator.
    ///
    /// The database will be synced to disc if `options.sync == true`. This is
    /// NOT the default.
    fn put(&self,
           options: WriteOptions,
           key: K,
           value: &[u8]) -> Result<(), Error>;
    /// delete a value from the database.
    ///
    /// The passed key will be compared using the comparator.
    ///
    /// The database will be synced to disc if `options.sync == true`. This is
    /// NOT the default.
    fn delete(&self,
              options: WriteOptions,
              key: K) -> Result<(), Error>;
}

impl<K: Key> KV<K> for Database<K> {
  /// put a binary value into the database.
  ///
  /// If the key is already present in the database, it will be overwritten.
  ///
  /// The passed key will be compared using the comparator.
  ///
  /// The database will be synced to disc if `options.sync == true`. This is
  /// NOT the default.
  fn put(&self,
             options: WriteOptions,
             key: K,
             value: &[u8]) -> Result<(), Error> {
    unsafe {
      key.as_slice(|k| {
        let mut error = ptr::null_mut();
        let c_writeoptions = c_writeoptions(options);
        leveldb_put(self.database.ptr,
                    c_writeoptions,
                    k.as_ptr() as *mut c_char,
                    k.len() as size_t,
                    value.as_ptr() as *mut c_char,
                    value.len() as size_t,
                    &mut error);
        leveldb_writeoptions_destroy(c_writeoptions);

        if error == ptr::null_mut() {
          Ok(())
        } else {
          Err(Error::new_from_i8(error))
        }
      })
    }
  }

  /// delete a value from the database.
  ///
  /// The passed key will be compared using the comparator.
  ///
  /// The database will be synced to disc if `options.sync == true`. This is
  /// NOT the default.
  fn delete(&self,
                options: WriteOptions,
                key: K) -> Result<(), Error> {
    unsafe {
      key.as_slice(|k| {
        let mut error = ptr::null_mut();
        let c_writeoptions = c_writeoptions(options);
        leveldb_delete(self.database.ptr,
                       c_writeoptions,
                       k.as_ptr() as *mut c_char,
                       k.len() as size_t,
                       &mut error);
        leveldb_writeoptions_destroy(c_writeoptions);
        if error == ptr::null_mut() {
          Ok(())
        } else {
          Err(Error::new_from_i8(error))
        }
      })
    }
  }

  /// get a value from the database.
  ///
  /// The passed key will be compared using the comparator.
  fn get<'a>(&self,
             options: ReadOptions<'a,K>,
             key: K) -> Result<Option<Vec<u8>>, Error> {
    unsafe {
      key.as_slice(|k| {
        let mut error = ptr::null_mut();
        let mut length: size_t = 0;
        let c_readoptions = c_readoptions(&options);
        let result = leveldb_get(self.database.ptr,
                                 c_readoptions,
                                 k.as_ptr() as *mut c_char,
                                 k.len() as size_t,
                                 &mut length,
                                 &mut error);
        leveldb_readoptions_destroy(c_readoptions);

        if error == ptr::null_mut() {
          if result == ptr::null_mut() {
            Ok(None)
          } else {
            let vec = from_raw_parts(result as *mut u8, length as usize).to_vec();
            leveldb_free(result as *mut c_void);
            Ok(Some(vec))
          }
        } else {
          Err(Error::new_from_i8(error))
        }
      })
    }
  }
}
<|endoftext|>


<commit_before>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use error::StatsError;
use result::Result;
use super::{Distribution, Univariate, Discrete};

/// Implements the [Discrete Uniform](https://en.wikipedia.org/wiki/Discrete_uniform_distribution)
/// distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{DiscreteUniform, Univariate, Discrete};
///
/// let n = DiscreteUniform::new(0, 5).unwrap();
/// assert_eq!(n.mean(), 2.5);
/// assert_eq!(n.pmf(3), 1.0 / 6.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DiscreteUniform {
    min: i64,
    max: i64,
}

impl DiscreteUniform {
    /// Constructs a new discrete uniform distribution
    pub fn new(min: i64, max: i64) -> Result<DiscreteUniform> {
        if max < min {
            Err(StatsError::BadParams)
        } else {
            Ok(DiscreteUniform {
                min: min,
                max: max,
            })
        }
    }
}

impl Sample<f64> for DiscreteUniform {
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for DiscreteUniform {
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution for DiscreteUniform {
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        r.gen_range(self.min, self.max + 1) as f64
    }
}

impl Univariate for DiscreteUniform {
    fn mean(&self) -> f64 {
        (self.min + self.max) as f64 / 2.0
    }

    fn variance(&self) -> f64 {
        let diff = (self.max - self.min) as f64;
        ((diff + 1.0) * (diff + 1.0) - 1.0) / 12.0
    }

    fn std_dev(&self) -> f64 {
        self.variance().sqrt()
    }

    fn entropy(&self) -> f64 {
        let diff = (self.max - self.min) as f64;
        (diff + 1.0).ln()
    }

    fn skewness(&self) -> f64 {
        0.0
    }

    fn median(&self) -> f64 {
        (self.min + self.max) as f64 / 2.0
    }

    fn cdf(&self, x: f64) -> f64 {
        if x < self.min as f64 {
            return 0.0;
        }
        if x >= self.max as f64 {
            return 1.0;
        }

        let lower = self.min as f64;
        let upper = self.max as f64;
        let ans = (x.floor() - lower + 1.0) / (upper - lower + 1.0);
        if x > 1.0 {
            1.0
        } else {
            ans
        }
    }
}

impl Discrete for DiscreteUniform {
    fn mode(&self) -> i64 {
        ((self.min + self.max) as f64 / 2.0).floor() as i64
    }

    fn min(&self) -> i64 {
        self.min
    }

    fn max(&self) -> i64 {
        self.max
    }

    fn pmf(&self, x: i64) -> f64 {
        if x >= self.min && x <= self.max {
            1.0 / (self.max - self.min + 1) as f64
        } else {
            0.0
        }
    }

    fn ln_pmf(&self, x: i64) -> f64 {
        if x >= self.min && x <= self.max {
            -((self.max - self.min + 1) as f64).ln()
        } else {
            f64::NEG_INFINITY
        }
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::cmp::PartialEq;
    use std::fmt::Debug;
    use std::f64;
    use distribution::{Univariate, Discrete};
    use super::DiscreteUniform;

    fn try_create(min: i64, max: i64) -> DiscreteUniform {
        let n = DiscreteUniform::new(min, max);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(min: i64, max: i64) {
        let n = try_create(min, max);
        assert_eq!(min, n.min());
        assert_eq!(max, n.max());
    }

    fn bad_create_case(min: i64, max: i64) {
        let n = DiscreteUniform::new(min, max);
        assert!(n.is_err());
    }

    fn test_case<T, F>(min: i64, max: i64, expected: T, eval: F)
        where T: PartialEq + Debug,
              F: Fn(DiscreteUniform) -> T
    {
        let n = try_create(min, max);
        let x = eval(n);
        assert_eq!(expected, x);
    }

    #[test]
    fn test_create() {
        create_case(-10, 10);
        create_case(0, 4);
        create_case(10, 20);
        create_case(20, 20);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(-1, -2);
        bad_create_case(6, 5);
    }

    #[test]
    fn test_mean() {
        test_case(-10, 10, 0.0, |x| x.mean());
        test_case(0, 4, 2.0, |x| x.mean());
        test_case(10, 20, 15.0, |x| x.mean());
        test_case(20, 20, 20.0, |x| x.mean());
    }

    #[test]
    fn test_variance() {
        test_case(-10, 10, 36.66666666666666666667, |x| x.variance());
        test_case(0, 4, 2.0, |x| x.variance());
        test_case(10, 20, 10.0, |x| x.variance());
        test_case(20, 20, 0.0, |x| x.variance());
    }

    #[test]
    fn test_std_dev() {
        test_case(-10, 10, (36.66666666666666666667f64).sqrt(), |x| x.std_dev());
        test_case(0, 4, (2.0f64).sqrt(), |x| x.std_dev());
        test_case(10, 20, (10.0f64).sqrt(), |x| x.std_dev());
        test_case(20, 20, 0.0, |x| x.std_dev());
    }

    #[test]
    fn test_entropy() {
        test_case(-10, 10, 3.0445224377234229965005979803657054342845752874046093, |x| x.entropy());
        test_case(0, 4, 1.6094379124341003746007593332261876395256013542685181, |x| x.entropy());
        test_case(10, 20, 2.3978952727983705440619435779651292998217068539374197, |x| x.entropy());
        test_case(20, 20, 0.0, |x| x.entropy());
    }

    #[test]
    fn test_skewness() {
        test_case(-10, 10, 0.0, |x| x.skewness());
        test_case(0, 4, 0.0, |x| x.skewness());
        test_case(10, 20, 0.0, |x| x.skewness());
        test_case(20, 20, 0.0, |x| x.skewness());
    }

    #[test]
    fn test_median() {
        test_case(-10, 10, 0.0, |x| x.median());
        test_case(0, 4, 2.0, |x| x.median());
        test_case(10, 20, 15.0, |x| x.median());
        test_case(20, 20, 20.0, |x| x.median());
    }

    #[test]
    fn test_mode() {
        test_case(-10, 10, 0, |x| x.mode());
        test_case(0, 4, 2, |x| x.mode());
        test_case(10, 20, 15, |x| x.mode());
        test_case(20, 20, 20, |x| x.mode());
    }

    #[test]
    fn test_pmf() {
        test_case(-10, 10, 0.04761904761904761904762, |x| x.pmf(-5));
        test_case(-10, 10, 0.04761904761904761904762, |x| x.pmf(1));
        test_case(-10, 10, 0.04761904761904761904762, |x| x.pmf(10));
        test_case(-10, -10, 0.0, |x| x.pmf(0));
        test_case(-10, -10, 1.0, |x| x.pmf(-10));
    }

    #[test]
    fn test_ln_pmf() {
        test_case(-10, 10, -3.0445224377234229965005979803657054342845752874046093, |x| x.ln_pmf(-5));
        test_case(-10, 10, -3.0445224377234229965005979803657054342845752874046093, |x| x.ln_pmf(1));
        test_case(-10, 10, -3.0445224377234229965005979803657054342845752874046093, |x| x.ln_pmf(10));
        test_case(-10, -10, f64::NEG_INFINITY, |x| x.ln_pmf(0));
        test_case(-10, -10, 0.0, |x| x.ln_pmf(-10));
    }

    #[test]
    fn test_cdf() {
        test_case(-10, 10, 0.2857142857142857142857, |x| x.cdf(-5.0));
        test_case(-10, 10, 0.5714285714285714285714, |x| x.cdf(1.0));
        test_case(-10, 10, 1.0, |x| x.cdf(10.0));
        test_case(-10, -10, 1.0, |x| x.cdf(0.0));
        test_case(-10, -10, 1.0, |x| x.cdf(-10.0));
        test_case(-10, -10, 0.0, |x| x.cdf(-11.0));
    }
}
<commit_msg>complete docs for discrete uniform<commit_after>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use error::StatsError;
use result::Result;
use super::{Distribution, Univariate, Discrete};

/// Implements the [Discrete Uniform](https://en.wikipedia.org/wiki/Discrete_uniform_distribution)
/// distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{DiscreteUniform, Univariate, Discrete};
///
/// let n = DiscreteUniform::new(0, 5).unwrap();
/// assert_eq!(n.mean(), 2.5);
/// assert_eq!(n.pmf(3), 1.0 / 6.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DiscreteUniform {
    min: i64,
    max: i64,
}

impl DiscreteUniform {
    /// Constructs a new discrete uniform distribution with a minimum value
    /// of `min` and a maximum value of `max`.
    ///
    /// # Errors
    ///
    /// Returns an error if `max < min`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::DiscreteUniform;
    ///
    /// let mut result = DiscreteUniform::new(0, 5);
    /// assert!(result.is_ok());
    ///
    /// result = DiscreteUniform::new(5, 0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(min: i64, max: i64) -> Result<DiscreteUniform> {
        if max < min {
            Err(StatsError::BadParams)
        } else {
            Ok(DiscreteUniform {
                min: min,
                max: max,
            })
        }
    }
}

impl Sample<f64> for DiscreteUniform {
    /// Generate a random sample from a discrete uniform
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for DiscreteUniform {
    /// Generate a random independent sample from a discrete uniform
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution for DiscreteUniform {
    /// Generate a random sample from the discrete uniform distribution
    /// using `r` as the source of randomness in the range `[min, max]`
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    ///
    /// use rand::StdRng;
    /// use statrs::distribution::{DiscreteUniform, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = DiscreteUniform::new(0, 5).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        r.gen_range(self.min, self.max + 1) as f64
    }
}

impl Univariate for DiscreteUniform {
    /// Returns the mean of the discrete uniform distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (min + max) / 2
    /// ```
    fn mean(&self) -> f64 {
        (self.min + self.max) as f64 / 2.0
    }

    /// Returns the variance of the discrete uniform distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ((max - min + 1)^2 - 1) / 12
    /// ```
    fn variance(&self) -> f64 {
        let diff = (self.max - self.min) as f64;
        ((diff + 1.0) * (diff + 1.0) - 1.0) / 12.0
    }

    /// Returns the standard deviation of the discrete uniform distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// sqrt(((max - min + 1)^2 - 1) / 12)
    /// ```
    fn std_dev(&self) -> f64 {
        self.variance().sqrt()
    }

    /// Returns the entropy of the discrete uniform distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(max - min + 1)
    /// ```
    fn entropy(&self) -> f64 {
        let diff = (self.max - self.min) as f64;
        (diff + 1.0).ln()
    }

    /// Returns the skewness of the discrete uniform distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 0
    /// ```
    fn skewness(&self) -> f64 {
        0.0
    }

    /// Returns the median of the discrete uniform distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (max + min) / 2
    /// ```
    fn median(&self) -> f64 {
        (self.min + self.max) as f64 / 2.0
    }

    /// Calculates the cumulative distribution function for the
    /// discrete uniform distribution at `x`
    ///
    /// # Remarks
    ///
    /// Returns `0.0` if `x < min` and `1.0` if `x >= max`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (floor(x) - min + 1) / (max - min + 1)
    /// ```
    fn cdf(&self, x: f64) -> f64 {
        if x < self.min as f64 {
            return 0.0;
        }
        if x >= self.max as f64 {
            return 1.0;
        }

        let lower = self.min as f64;
        let upper = self.max as f64;
        let ans = (x.floor() - lower + 1.0) / (upper - lower + 1.0);
        if ans > 1.0 {
            1.0
        } else {
            ans
        }
    }
}

impl Discrete for DiscreteUniform {
    /// Returns the mode for the discrete uniform distribution
    ///
    /// # Remarks
    ///
    /// Since every element has an equal probability, mode simply
    /// returns the middle element
    ///
    /// # Formula
    ///
    /// ```ignore
    /// N/A // (max + min) / 2 for the middle element
    /// ```
    fn mode(&self) -> i64 {
        ((self.min + self.max) as f64 / 2.0).floor() as i64
    }

    /// Returns the minimum value in the domain of the discrete uniform
    /// distribution
    ///
    /// # Remarks
    ///
    /// This is the same value as the minimum passed into the constructor
    fn min(&self) -> i64 {
        self.min
    }

    /// Returns the maximum value in the domain of the discrete uniform
    /// distribution
    ///
    /// # Remarks
    ///
    /// This is the same value as the maximum passed into the constructor
    fn max(&self) -> i64 {
        self.max
    }

    /// Calculates the probability mass function for the discrete uniform
    /// distribution at `x`
    ///
    /// # Remarks
    ///
    /// Returns `0.0` if `x` is not in `[min, max]`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 1 / (max - min + 1)
    /// ```
    fn pmf(&self, x: i64) -> f64 {
        if x >= self.min && x <= self.max {
            1.0 / (self.max - self.min + 1) as f64
        } else {
            0.0
        }
    }

    /// Calculates the log probability mass function for the discrete uniform
    /// distribution at `x`
    ///
    /// # Remarks
    ///
    /// Returns `f64::NEG_INFINITY` if `x` is not in `[min, max]`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(1 / (max - min + 1))
    /// ```
    fn ln_pmf(&self, x: i64) -> f64 {
        if x >= self.min && x <= self.max {
            -((self.max - self.min + 1) as f64).ln()
        } else {
            f64::NEG_INFINITY
        }
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::cmp::PartialEq;
    use std::fmt::Debug;
    use std::f64;
    use distribution::{Univariate, Discrete};
    use super::DiscreteUniform;

    fn try_create(min: i64, max: i64) -> DiscreteUniform {
        let n = DiscreteUniform::new(min, max);
        assert!(n.is_ok());
        n.unwrap()
    }

    fn create_case(min: i64, max: i64) {
        let n = try_create(min, max);
        assert_eq!(min, n.min());
        assert_eq!(max, n.max());
    }

    fn bad_create_case(min: i64, max: i64) {
        let n = DiscreteUniform::new(min, max);
        assert!(n.is_err());
    }

    fn test_case<T, F>(min: i64, max: i64, expected: T, eval: F)
        where T: PartialEq + Debug,
              F: Fn(DiscreteUniform) -> T
    {
        let n = try_create(min, max);
        let x = eval(n);
        assert_eq!(expected, x);
    }

    #[test]
    fn test_create() {
        create_case(-10, 10);
        create_case(0, 4);
        create_case(10, 20);
        create_case(20, 20);
    }

    #[test]
    fn test_bad_create() {
        bad_create_case(-1, -2);
        bad_create_case(6, 5);
    }

    #[test]
    fn test_mean() {
        test_case(-10, 10, 0.0, |x| x.mean());
        test_case(0, 4, 2.0, |x| x.mean());
        test_case(10, 20, 15.0, |x| x.mean());
        test_case(20, 20, 20.0, |x| x.mean());
    }

    #[test]
    fn test_variance() {
        test_case(-10, 10, 36.66666666666666666667, |x| x.variance());
        test_case(0, 4, 2.0, |x| x.variance());
        test_case(10, 20, 10.0, |x| x.variance());
        test_case(20, 20, 0.0, |x| x.variance());
    }

    #[test]
    fn test_std_dev() {
        test_case(-10, 10, (36.66666666666666666667f64).sqrt(), |x| x.std_dev());
        test_case(0, 4, (2.0f64).sqrt(), |x| x.std_dev());
        test_case(10, 20, (10.0f64).sqrt(), |x| x.std_dev());
        test_case(20, 20, 0.0, |x| x.std_dev());
    }

    #[test]
    fn test_entropy() {
        test_case(-10, 10, 3.0445224377234229965005979803657054342845752874046093, |x| x.entropy());
        test_case(0, 4, 1.6094379124341003746007593332261876395256013542685181, |x| x.entropy());
        test_case(10, 20, 2.3978952727983705440619435779651292998217068539374197, |x| x.entropy());
        test_case(20, 20, 0.0, |x| x.entropy());
    }

    #[test]
    fn test_skewness() {
        test_case(-10, 10, 0.0, |x| x.skewness());
        test_case(0, 4, 0.0, |x| x.skewness());
        test_case(10, 20, 0.0, |x| x.skewness());
        test_case(20, 20, 0.0, |x| x.skewness());
    }

    #[test]
    fn test_median() {
        test_case(-10, 10, 0.0, |x| x.median());
        test_case(0, 4, 2.0, |x| x.median());
        test_case(10, 20, 15.0, |x| x.median());
        test_case(20, 20, 20.0, |x| x.median());
    }

    #[test]
    fn test_mode() {
        test_case(-10, 10, 0, |x| x.mode());
        test_case(0, 4, 2, |x| x.mode());
        test_case(10, 20, 15, |x| x.mode());
        test_case(20, 20, 20, |x| x.mode());
    }

    #[test]
    fn test_pmf() {
        test_case(-10, 10, 0.04761904761904761904762, |x| x.pmf(-5));
        test_case(-10, 10, 0.04761904761904761904762, |x| x.pmf(1));
        test_case(-10, 10, 0.04761904761904761904762, |x| x.pmf(10));
        test_case(-10, -10, 0.0, |x| x.pmf(0));
        test_case(-10, -10, 1.0, |x| x.pmf(-10));
    }

    #[test]
    fn test_ln_pmf() {
        test_case(-10, 10, -3.0445224377234229965005979803657054342845752874046093, |x| x.ln_pmf(-5));
        test_case(-10, 10, -3.0445224377234229965005979803657054342845752874046093, |x| x.ln_pmf(1));
        test_case(-10, 10, -3.0445224377234229965005979803657054342845752874046093, |x| x.ln_pmf(10));
        test_case(-10, -10, f64::NEG_INFINITY, |x| x.ln_pmf(0));
        test_case(-10, -10, 0.0, |x| x.ln_pmf(-10));
    }

    #[test]
    fn test_cdf() {
        test_case(-10, 10, 0.2857142857142857142857, |x| x.cdf(-5.0));
        test_case(-10, 10, 0.5714285714285714285714, |x| x.cdf(1.0));
        test_case(-10, 10, 1.0, |x| x.cdf(10.0));
        test_case(-10, -10, 1.0, |x| x.cdf(0.0));
        test_case(-10, -10, 1.0, |x| x.cdf(-10.0));
        test_case(-10, -10, 0.0, |x| x.cdf(-11.0));
    }
}
<|endoftext|>