<commit_before>use int::{Int, CastInto};
use float::Float;

#[derive(Clone, Copy)]
enum Result {
    Less,
    Equal,
    Greater,
    Unordered
}

impl Result {
    fn to_le_abi(self) -> i32 {
        match self {
            Result::Less      => -1,
            Result::Equal     => 0,
            Result::Greater   => 1,
            Result::Unordered => 1
        }
    }

    fn to_ge_abi(self) -> i32 {
        match self {
            Result::Less      => -1,
            Result::Equal     => 0,
            Result::Greater   => 1,
            Result::Unordered => -1
        }
    }
}

fn cmp<F: Float>(a: F, b: F) -> Result where
    u32: CastInto<F::Int>,
    F::Int: CastInto<u32>,
    i32: CastInto<F::Int>,
    F::Int: CastInto<i32>,
{
    let one = F::Int::ONE;
    let zero = F::Int::ZERO;

    let sign_bit =      F::SIGN_MASK as F::Int;
    let abs_mask =      sign_bit - one;
    let exponent_mask = F::EXPONENT_MASK;
    let inf_rep =       exponent_mask;

    let a_rep = a.repr();
    let b_rep = b.repr();
    let a_abs = a_rep & abs_mask;
    let b_abs = b_rep & abs_mask;

    // If either a or b is NaN, they are unordered.
    if a_abs > inf_rep || b_abs > inf_rep {
        return Result::Unordered
    }

    // If a and b are both zeros, they are equal.
    if a_abs | b_abs == zero {
        return Result::Equal
    }

    // If at least one of a and b is positive, we get the same result comparing
    // a and b as signed integers as we would with a fp_ting-point compare.
    if a_rep & b_rep >= zero {
        if a_rep < b_rep {
            return Result::Less
        } else if a_rep == b_rep {
            return Result::Equal
        } else {
            return Result::Greater
        }
    }

    // Otherwise, both are negative, so we need to flip the sense of the
    // comparison to get the correct result.  (This assumes a twos- or ones-
    // complement integer representation; if integers are represented in a
    // sign-magnitude representation, then this flip is incorrect).
    else {
        if a_rep > b_rep {
            return Result::Less
        } else if a_rep == b_rep {
            return Result::Equal
        } else {
            return Result::Greater
        }
    }
}
fn unord<F: Float>(a: F, b: F) -> bool where
    u32: CastInto<F::Int>,
    F::Int: CastInto<u32>,
    i32: CastInto<F::Int>,
    F::Int: CastInto<i32>,
{
    let one = F::Int::ONE;

    let sign_bit =      F::SIGN_MASK as F::Int;
    let abs_mask =      sign_bit - one;
    let exponent_mask = F::EXPONENT_MASK;
    let inf_rep =       exponent_mask;

    let a_rep = a.repr();
    let b_rep = b.repr();
    let a_abs = a_rep & abs_mask;
    let b_abs = b_rep & abs_mask;

    a_abs > inf_rep || b_abs > inf_rep
}

intrinsics! {
    pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_ge_abi()
    }

    #[arm_aeabi_alias = fcmpun]
    pub extern "C" fn __unordsf2(a: f32, b: f32) -> bool {
        unord(a, b)
    }

    pub extern "C" fn __eqsf2(a: f32, b: f32) -> bool {
        cmp(a, b).to_le_abi() != 0
    }

    pub extern "C" fn __ltsf2(a: f32, b: f32) -> bool {
        cmp(a, b).to_le_abi() != 0
    }

    pub extern "C" fn __nesf2(a: f32, b: f32) -> bool {
        cmp(a, b).to_le_abi() != 0
    }

    pub extern "C" fn __gtsf2(a: f32, b: f32) -> bool {
        cmp(a, b).to_ge_abi() != 0
    }

    pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 {
        cmp(a, b).to_ge_abi()
    }

    #[arm_aeabi_alias = dcmpun]
    pub extern "C" fn __unorddf2(a: f64, b: f64) -> bool {
        unord(a, b)
    }

    pub extern "C" fn __eqdf2(a: f64, b: f64) -> bool {
        cmp(a, b).to_le_abi() != 0
    }

    pub extern "C" fn __ltdf2(a: f64, b: f64) -> bool {
        cmp(a, b).to_le_abi() != 0
    }

    pub extern "C" fn __nedf2(a: f64, b: f64) -> bool {
        cmp(a, b).to_le_abi() != 0
    }

    pub extern "C" fn __gtdf2(a: f32, b: f32) -> bool {
        cmp(a, b).to_ge_abi() != 0
    }
}
<commit_msg>comparesf2/comparedf2: use i32 instead of bool for return type.<commit_after>use int::{Int, CastInto};
use float::Float;

#[derive(Clone, Copy)]
enum Result {
    Less,
    Equal,
    Greater,
    Unordered
}

impl Result {
    fn to_le_abi(self) -> i32 {
        match self {
            Result::Less      => -1,
            Result::Equal     => 0,
            Result::Greater   => 1,
            Result::Unordered => 1
        }
    }

    fn to_ge_abi(self) -> i32 {
        match self {
            Result::Less      => -1,
            Result::Equal     => 0,
            Result::Greater   => 1,
            Result::Unordered => -1
        }
    }
}

fn cmp<F: Float>(a: F, b: F) -> Result where
    u32: CastInto<F::Int>,
    F::Int: CastInto<u32>,
    i32: CastInto<F::Int>,
    F::Int: CastInto<i32>,
{
    let one = F::Int::ONE;
    let zero = F::Int::ZERO;

    let sign_bit =      F::SIGN_MASK as F::Int;
    let abs_mask =      sign_bit - one;
    let exponent_mask = F::EXPONENT_MASK;
    let inf_rep =       exponent_mask;

    let a_rep = a.repr();
    let b_rep = b.repr();
    let a_abs = a_rep & abs_mask;
    let b_abs = b_rep & abs_mask;

    // If either a or b is NaN, they are unordered.
    if a_abs > inf_rep || b_abs > inf_rep {
        return Result::Unordered
    }

    // If a and b are both zeros, they are equal.
    if a_abs | b_abs == zero {
        return Result::Equal
    }

    // If at least one of a and b is positive, we get the same result comparing
    // a and b as signed integers as we would with a fp_ting-point compare.
    if a_rep & b_rep >= zero {
        if a_rep < b_rep {
            return Result::Less
        } else if a_rep == b_rep {
            return Result::Equal
        } else {
            return Result::Greater
        }
    }

    // Otherwise, both are negative, so we need to flip the sense of the
    // comparison to get the correct result.  (This assumes a twos- or ones-
    // complement integer representation; if integers are represented in a
    // sign-magnitude representation, then this flip is incorrect).
    else {
        if a_rep > b_rep {
            return Result::Less
        } else if a_rep == b_rep {
            return Result::Equal
        } else {
            return Result::Greater
        }
    }
}
fn unord<F: Float>(a: F, b: F) -> bool where
    u32: CastInto<F::Int>,
    F::Int: CastInto<u32>,
    i32: CastInto<F::Int>,
    F::Int: CastInto<i32>,
{
    let one = F::Int::ONE;

    let sign_bit =      F::SIGN_MASK as F::Int;
    let abs_mask =      sign_bit - one;
    let exponent_mask = F::EXPONENT_MASK;
    let inf_rep =       exponent_mask;

    let a_rep = a.repr();
    let b_rep = b.repr();
    let a_abs = a_rep & abs_mask;
    let b_abs = b_rep & abs_mask;

    a_abs > inf_rep || b_abs > inf_rep
}

intrinsics! {
    pub extern "C" fn __lesf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __gesf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_ge_abi()
    }

    #[arm_aeabi_alias = fcmpun]
    pub extern "C" fn __unordsf2(a: f32, b: f32) -> i32 {
        unord(a, b) as i32
    }

    pub extern "C" fn __eqsf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __ltsf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __nesf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __gtsf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_ge_abi()
    }

    pub extern "C" fn __ledf2(a: f64, b: f64) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __gedf2(a: f64, b: f64) -> i32 {
        cmp(a, b).to_ge_abi()
    }

    #[arm_aeabi_alias = dcmpun]
    pub extern "C" fn __unorddf2(a: f64, b: f64) -> i32 {
        unord(a, b) as i32
    }

    pub extern "C" fn __eqdf2(a: f64, b: f64) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __ltdf2(a: f64, b: f64) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __nedf2(a: f64, b: f64) -> i32 {
        cmp(a, b).to_le_abi()
    }

    pub extern "C" fn __gtdf2(a: f32, b: f32) -> i32 {
        cmp(a, b).to_ge_abi()
    }
}
<|endoftext|>


<commit_before>//!
//! A static environment is used to store a fixed set of tools.
//!

use std::sync::Arc;
use std::collections::HashMap;
use std::result::Result;
use serde_json::*;

use super::super::tool::*;
use super::super::environment::*;
use super::toolset::*;

///
/// A static environment just contains a fixed set of tools
///
pub struct StaticEnvironment {
    /// The tools in this environment
    tools: HashMap<String, Arc<Box<Tool>>>
}

///
/// Wrapper for a tool from a static environment
///
struct StaticEnvironmentTool {
    /// Reference to the tool within the environment
    tool: Arc<Box<Tool>>
}

impl Tool for StaticEnvironmentTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        (**self.tool).invoke_json(input, environment)
    }
}

impl Environment for StaticEnvironment {
    ///
    /// Retrieves a tool using a JSON interface by name
    ///
    fn get_json_tool(&self, name: &str) -> Result<Box<Tool>, RetrieveToolError> {
        let tool = self.tools.get(&String::from(name));

        match tool {
            Some(tool)  => Ok(Box::new(StaticEnvironmentTool { tool: tool.clone() })),
            None        => Err(RetrieveToolError::not_found())
        }
    }
}

impl StaticEnvironment {
    ///
    /// Creates a new static environment from a toolset
    ///
    pub fn from_toolset<T: ToolSet>(set: T, environment: &Environment) -> StaticEnvironment {
        let tools           = set.create_tools(environment);
        let mut tool_hash   = HashMap::new();

        for tool_and_name in tools {
            let (name, tool) = tool_and_name;

            tool_hash.insert(name, Arc::new(tool));
        }

        StaticEnvironment { tools: tool_hash }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::functional_tool::*;
    use super::super::empty_environment::*;
    use super::super::basic_toolset::*;

    #[test]
    fn can_get_tool_by_name() {
        let toolset = BasicToolSet::from(vec![
            ("add-1", make_pure_tool(|x: i32| { x+1 })),
            ("add-2", make_pure_tool(|x: i32| { x+2 }))
        ]);
        let environment = StaticEnvironment::from_toolset(toolset, &EmptyEnvironment::new());

        assert!(environment.get_json_tool("add-1").is_ok());
        assert!(environment.get_json_tool("add-2").is_ok());
    }

    #[test]
    fn error_for_missing_tool() {
        let toolset = BasicToolSet::from(vec![
            ("add-1", make_pure_tool(|x: i32| { x+1 })),
            ("add-2", make_pure_tool(|x: i32| { x+2 }))
        ]);
        let environment = StaticEnvironment::from_toolset(toolset, &EmptyEnvironment::new());

        assert!(environment.get_json_tool("add-3").is_err());
    }

    #[test]
    fn tools_are_right() {
        let toolset = BasicToolSet::from(vec![
            ("add-1", make_pure_tool(|x: i32| { x+1 })),
            ("add-2", make_pure_tool(|x: i32| { x+2 }))
        ]);
        let environment = StaticEnvironment::from_toolset(toolset, &EmptyEnvironment::new());

        let add1 = environment.get_json_tool("add-1").unwrap();
        let add2 = environment.get_json_tool("add-2").unwrap();

        assert!(add1.invoke_json(json![ 2 ], &environment) == Ok(json![ 3 ]));
        assert!(add2.invoke_json(json![ 2 ], &environment) == Ok(json![ 4 ]));
    }
}
<commit_msg>Add a way to create a static environment containing a single tool<commit_after>//!
//! A static environment is used to store a fixed set of tools.
//!

use std::sync::Arc;
use std::collections::HashMap;
use std::result::Result;
use serde_json::*;

use super::super::tool::*;
use super::super::environment::*;
use super::toolset::*;
use super::basic_toolset::*;

///
/// A static environment just contains a fixed set of tools
///
pub struct StaticEnvironment {
    /// The tools in this environment
    tools: HashMap<String, Arc<Box<Tool>>>
}

///
/// Wrapper for a tool from a static environment
///
struct StaticEnvironmentTool {
    /// Reference to the tool within the environment
    tool: Arc<Box<Tool>>
}

impl Tool for StaticEnvironmentTool {
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        (**self.tool).invoke_json(input, environment)
    }
}

impl Environment for StaticEnvironment {
    ///
    /// Retrieves a tool using a JSON interface by name
    ///
    fn get_json_tool(&self, name: &str) -> Result<Box<Tool>, RetrieveToolError> {
        let tool = self.tools.get(&String::from(name));

        match tool {
            Some(tool)  => Ok(Box::new(StaticEnvironmentTool { tool: tool.clone() })),
            None        => Err(RetrieveToolError::not_found())
        }
    }
}

impl StaticEnvironment {
    ///
    /// Creates a new static environment from a toolset
    ///
    pub fn from_toolset<T: ToolSet>(set: T, environment: &Environment) -> StaticEnvironment {
        let tools           = set.create_tools(environment);
        let mut tool_hash   = HashMap::new();

        for tool_and_name in tools {
            let (name, tool) = tool_and_name;

            tool_hash.insert(name, Arc::new(tool));
        }

        StaticEnvironment { tools: tool_hash }
    }

    ///
    /// Creates a new static environment containing a single tool
    ///
    pub fn from_tool<T: Tool+'static>(tool_name: &str, tool: T, environment: &Environment) -> StaticEnvironment {
        // Create a toolset containing this tool
        let single_toolset = BasicToolSet::from(vec![ (String::from(tool_name), tool) ]);

        // Pass through to from_toolset
        StaticEnvironment::from_toolset(single_toolset, environment)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::functional_tool::*;
    use super::super::empty_environment::*;
    use super::super::basic_toolset::*;

    #[test]
    fn can_get_tool_by_name() {
        let toolset = BasicToolSet::from(vec![
            ("add-1", make_pure_tool(|x: i32| { x+1 })),
            ("add-2", make_pure_tool(|x: i32| { x+2 }))
        ]);
        let environment = StaticEnvironment::from_toolset(toolset, &EmptyEnvironment::new());

        assert!(environment.get_json_tool("add-1").is_ok());
        assert!(environment.get_json_tool("add-2").is_ok());
    }

    #[test]
    fn error_for_missing_tool() {
        let toolset = BasicToolSet::from(vec![
            ("add-1", make_pure_tool(|x: i32| { x+1 })),
            ("add-2", make_pure_tool(|x: i32| { x+2 }))
        ]);
        let environment = StaticEnvironment::from_toolset(toolset, &EmptyEnvironment::new());

        assert!(environment.get_json_tool("add-3").is_err());
    }

    #[test]
    fn tools_are_right() {
        let toolset = BasicToolSet::from(vec![
            ("add-1", make_pure_tool(|x: i32| { x+1 })),
            ("add-2", make_pure_tool(|x: i32| { x+2 }))
        ]);
        let environment = StaticEnvironment::from_toolset(toolset, &EmptyEnvironment::new());

        let add1 = environment.get_json_tool("add-1").unwrap();
        let add2 = environment.get_json_tool("add-2").unwrap();

        assert!(add1.invoke_json(json![ 2 ], &environment) == Ok(json![ 3 ]));
        assert!(add2.invoke_json(json![ 2 ], &environment) == Ok(json![ 4 ]));
    }
}
<|endoftext|>


<commit_before>use uuid::Uuid;
use chrono::NaiveDateTime;

use schema::aardwolf::accounts;

#[derive(Queryable, Identifiable)]
#[allow(unused_must_use, dead_code)]
pub(crate) struct Account {
    pub id: Uuid,
    username: String,
    domain: Option<String>,
    display_name: String,
    created_at: NaiveDateTime,
    updated_at: NaiveDateTime,
}

#[derive(Insertable)]
#[table_name="accounts"]
pub(crate) struct NewAccount {
    pub username: String,
}
<commit_msg>don't ignore these<commit_after>use uuid::Uuid;
use chrono::NaiveDateTime;

use schema::aardwolf::accounts;

#[derive(Queryable, Identifiable)]
pub(crate) struct Account {
    pub id: Uuid,
    username: String,
    domain: Option<String>,
    display_name: String,
    created_at: NaiveDateTime,
    updated_at: NaiveDateTime,
}

#[derive(Insertable)]
#[table_name="accounts"]
pub(crate) struct NewAccount {
    pub username: String,
}
<|endoftext|>


<commit_before>use {TypedDecider, ImpliedDeciderImpl, MultiDeciderImpl, Decider, MultiDecider, Decision,
     Threadsafe, Result, ErrorKind};

use std::time::{Instant, Duration};
use std::cmp;

impl Decider for LeakyBucket {}

impl MultiDecider for LeakyBucket {}

impl TypedDecider for LeakyBucket {
    /// The leaky bucket can provide an approximation for how long to
    /// sleep until one token is available again. (This does not
    /// account for multiple requests attempting to use the same
    /// token; schedulers relying on this must account for phenomena
    /// like thundering herds.)
    type T = Duration;
}

#[derive(Debug, Clone)]
/// Implements the industry-standard leaky bucket rate-limiting
/// as-a-meter. The bucket keeps a "fill height", pretending to drip
/// steadily (which reduces the fill height), and increases the fill
/// height with every cell that is found conforming. If cells would
/// make the bucket overflow, they count as non-conforming.
///
/// # Drip implementation
///
/// Instead of having a background task update the bucket's fill
/// level, this implementation re-computes the fill level of the
/// bucket on every call to [`check`](#method.check) and related
/// methods.
///
/// # Wait time calculation
///
/// If the cell does not fit, this implementation computes the minimum
/// wait time until the cell can be accomodated. This minimum wait
/// time does not account for thundering herd effects or other
/// problems in concurrent resource acquisition, so users of this
/// library must take care to apply positive jitter to these wait
/// times.
///
/// # Example
/// ``` rust
/// # use ratelimit_meter::{Decider, LeakyBucket, Decision};
/// let mut lb: LeakyBucket = LeakyBucket::per_second(2).unwrap();
/// assert_eq!(Decision::Yes, lb.check().unwrap());
/// ```
pub struct LeakyBucket {
    last: Option<Instant>,
    full: Duration,
    current: Duration,
    token_interval: Duration,
}

impl LeakyBucket {
    /// Constructs and returns a leaky-bucket rate-limiter allowing as
    /// many cells on average as the given capacity per time duration.
    /// ## Example
    /// ``` rust
    /// # use ratelimit_meter::{Decider, LeakyBucket};
    /// # use std::time::{Duration, Instant};
    /// let now = Instant::now();
    /// let day = Duration::from_secs(86400);
    /// let mut lb = LeakyBucket::new(1, day).unwrap(); // 1 per day
    /// assert!(lb.check_at(now).unwrap().is_compliant());
    ///
    /// assert!(!lb.check_at(now + day/2).unwrap().is_compliant()); // Can't do it half a day later
    /// assert!(lb.check_at(now + day).unwrap().is_compliant()); // Have to wait a day
    /// assert!(lb.check_at(now + day * 2).unwrap().is_compliant()); // ...and then, a day after that.
    /// ```
    pub fn new(capacity: u32, per_duration: Duration) -> Result<LeakyBucket> {
        if capacity == 0 {
            return Err(ErrorKind::InconsistentCapacity(capacity, 0).into());
        }
        let token_interval = per_duration / capacity;
        Ok(LeakyBucket {
            last: None,
            current: Duration::new(0, 0),
            token_interval: token_interval,
            full: per_duration,
        })
    }

    /// Constructs and returns a leaky-bucket rate-limiter allowing on
    /// average `capacity`/1s cells.
    pub fn per_second(capacity: u32) -> Result<LeakyBucket> {
        LeakyBucket::new(capacity, Duration::from_secs(1))
    }

    /// Wraps the current leaky bucket in a
    /// [`Threadsafe`](../struct.Threadsafe.html).
    pub fn threadsafe(self) -> Threadsafe<LeakyBucket> {
        Threadsafe::new(self)
    }
}

impl MultiDeciderImpl for LeakyBucket {
    fn test_n_and_update(&mut self, n: u32, t0: Instant) -> Result<Decision<Duration>> {
        if self.token_interval * n > self.full {
            return Err(ErrorKind::InsufficientCapacity(n).into());
        }

        let current = self.current;
        let last = match self.last {
            None => {
                self.last = Some(t0);
                t0
            }
            Some(t) => t,
        };
        // Prevent time travel: If any parallel calls get re-ordered,
        // or any tests attempt silly things, make sure to answer from
        // the last query onwards instead.
        let t0 = cmp::max(t0, last);

        self.current = current - cmp::min(t0 - last, current);
        self.last = Some(t0);

        let weight = self.token_interval * n;
        if weight + self.current <= self.full {
            self.current = self.current + weight;
            Ok(Decision::Yes)
        } else {
            let wait_period = (weight + current) - self.full;
            Ok(Decision::No(wait_period))
        }
    }
}

impl ImpliedDeciderImpl for LeakyBucket {}
<commit_msg>Clippy: Use assign operation.<commit_after>use {TypedDecider, ImpliedDeciderImpl, MultiDeciderImpl, Decider, MultiDecider, Decision,
     Threadsafe, Result, ErrorKind};

use std::time::{Instant, Duration};
use std::cmp;

impl Decider for LeakyBucket {}

impl MultiDecider for LeakyBucket {}

impl TypedDecider for LeakyBucket {
    /// The leaky bucket can provide an approximation for how long to
    /// sleep until one token is available again. (This does not
    /// account for multiple requests attempting to use the same
    /// token; schedulers relying on this must account for phenomena
    /// like thundering herds.)
    type T = Duration;
}

#[derive(Debug, Clone)]
/// Implements the industry-standard leaky bucket rate-limiting
/// as-a-meter. The bucket keeps a "fill height", pretending to drip
/// steadily (which reduces the fill height), and increases the fill
/// height with every cell that is found conforming. If cells would
/// make the bucket overflow, they count as non-conforming.
///
/// # Drip implementation
///
/// Instead of having a background task update the bucket's fill
/// level, this implementation re-computes the fill level of the
/// bucket on every call to [`check`](#method.check) and related
/// methods.
///
/// # Wait time calculation
///
/// If the cell does not fit, this implementation computes the minimum
/// wait time until the cell can be accomodated. This minimum wait
/// time does not account for thundering herd effects or other
/// problems in concurrent resource acquisition, so users of this
/// library must take care to apply positive jitter to these wait
/// times.
///
/// # Example
/// ``` rust
/// # use ratelimit_meter::{Decider, LeakyBucket, Decision};
/// let mut lb: LeakyBucket = LeakyBucket::per_second(2).unwrap();
/// assert_eq!(Decision::Yes, lb.check().unwrap());
/// ```
pub struct LeakyBucket {
    last: Option<Instant>,
    full: Duration,
    current: Duration,
    token_interval: Duration,
}

impl LeakyBucket {
    /// Constructs and returns a leaky-bucket rate-limiter allowing as
    /// many cells on average as the given capacity per time duration.
    /// ## Example
    /// ``` rust
    /// # use ratelimit_meter::{Decider, LeakyBucket};
    /// # use std::time::{Duration, Instant};
    /// let now = Instant::now();
    /// let day = Duration::from_secs(86400);
    /// let mut lb = LeakyBucket::new(1, day).unwrap(); // 1 per day
    /// assert!(lb.check_at(now).unwrap().is_compliant());
    ///
    /// assert!(!lb.check_at(now + day/2).unwrap().is_compliant()); // Can't do it half a day later
    /// assert!(lb.check_at(now + day).unwrap().is_compliant()); // Have to wait a day
    /// assert!(lb.check_at(now + day * 2).unwrap().is_compliant()); // ...and then, a day after that.
    /// ```
    pub fn new(capacity: u32, per_duration: Duration) -> Result<LeakyBucket> {
        if capacity == 0 {
            return Err(ErrorKind::InconsistentCapacity(capacity, 0).into());
        }
        let token_interval = per_duration / capacity;
        Ok(LeakyBucket {
            last: None,
            current: Duration::new(0, 0),
            token_interval: token_interval,
            full: per_duration,
        })
    }

    /// Constructs and returns a leaky-bucket rate-limiter allowing on
    /// average `capacity`/1s cells.
    pub fn per_second(capacity: u32) -> Result<LeakyBucket> {
        LeakyBucket::new(capacity, Duration::from_secs(1))
    }

    /// Wraps the current leaky bucket in a
    /// [`Threadsafe`](../struct.Threadsafe.html).
    pub fn threadsafe(self) -> Threadsafe<LeakyBucket> {
        Threadsafe::new(self)
    }
}

impl MultiDeciderImpl for LeakyBucket {
    fn test_n_and_update(&mut self, n: u32, t0: Instant) -> Result<Decision<Duration>> {
        if self.token_interval * n > self.full {
            return Err(ErrorKind::InsufficientCapacity(n).into());
        }

        let current = self.current;
        let last = match self.last {
            None => {
                self.last = Some(t0);
                t0
            }
            Some(t) => t,
        };
        // Prevent time travel: If any parallel calls get re-ordered,
        // or any tests attempt silly things, make sure to answer from
        // the last query onwards instead.
        let t0 = cmp::max(t0, last);

        self.current = current - cmp::min(t0 - last, current);
        self.last = Some(t0);

        let weight = self.token_interval * n;
        if weight + self.current <= self.full {
            self.current += weight;
            Ok(Decision::Yes)
        } else {
            let wait_period = (weight + current) - self.full;
            Ok(Decision::No(wait_period))
        }
    }
}

impl ImpliedDeciderImpl for LeakyBucket {}
<|endoftext|>


<commit_before>use cairo;
use gio;
use glib;
use librsvg;
use rsvg_internals;

mod utils;

use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use self::utils::{compare_to_file, compare_to_surface, load_svg, render_to_viewport, SurfaceSize};

#[test]
fn render_to_viewport_with_different_size() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <rect x="8" y="8" width="32" height="32" fill="blue"/>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(128, 128),
        |_cr| (),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 128.0,
            height: 128.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 128, 128).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf);

        cr.scale(128.0 / 48.0, 128.0 / 48.0);

        cr.rectangle(8.0, 8.0, 32.0, 32.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
        cr.fill();
    }

    let reference_surf = SharedImageSurface::new(reference_surf, SurfaceType::SRgb).unwrap();

    compare_to_surface(
        &output_surf,
        &reference_surf,
        "render_to_viewport_with_different_size",
    );
}

#[test]
fn render_to_offsetted_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <rect x="8" y="8" width="32" height="32" fill="blue"/>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(100, 100),
        |_cr| (),
        cairo::Rectangle {
            x: 10.0,
            y: 20.0,
            width: 48.0,
            height: 48.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf);

        cr.translate(10.0, 20.0);

        cr.rectangle(8.0, 8.0, 32.0, 32.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
        cr.fill();
    }

    let reference_surf = SharedImageSurface::new(reference_surf, SurfaceType::SRgb).unwrap();

    compare_to_surface(
        &output_surf,
        &reference_surf,
        "render_to_offseted_viewport",
    );
}

#[test]
fn render_to_viewport_with_transform() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <g transform="translate(-10, -10)">
    <path fill="blue" d="M 18 18 l 32 0 l 0 32 l -32 0 z"/>
  </g>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(100, 100),
        |cr| cr.translate(10.0, 20.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 48.0,
            height: 48.0,
        },
    )
    .unwrap();

    compare_to_file(
        &output_surf,
        "render_to_viewport_with_transform",
        "rect-48x48-offsetted-100x100-10x20.png",
    );
}

#[test]
fn clip_on_transformed_viewport() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <defs>
    <clipPath id="one" clipPathUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.5"/>
    </clipPath>
  </defs>
  <g clip-path="url(#one)">
    <rect x="10" y="10" width="40" height="40" fill="blue"/>
    <rect x="50" y="50" width="40" height="40" fill="limegreen"/>
  </g>
</svg>
"##,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(200, 200),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    )
    .unwrap();

    compare_to_file(
        &output_surf,
        "clip_on_transformed_viewport",
        "clip-on-transformed-viewport-200x200.png",
    );
}

#[test]
fn mask_on_transformed_viewport() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <defs>
    <mask id="one" maskContentUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.5" fill="white"/>
    </mask>
  </defs>
  <g mask="url(#one)">
    <rect x="10" y="10" width="40" height="40" fill="blue"/>
    <rect x="50" y="50" width="40" height="40" fill="limegreen"/>
  </g>
</svg>
"##,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(200, 200),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    )
    .unwrap();

    compare_to_file(
        &output_surf,
        "mask_on_transformed_viewport",
        "mask-on-transformed-viewport-200x200.png",
    );
}
<commit_msg>render_to_viewport_with_transform(): Convert to reftest<commit_after>use cairo;
use gio;
use glib;
use librsvg;
use rsvg_internals;

mod utils;

use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use self::utils::{compare_to_file, compare_to_surface, load_svg, render_to_viewport, SurfaceSize};

#[test]
fn render_to_viewport_with_different_size() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <rect x="8" y="8" width="32" height="32" fill="blue"/>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(128, 128),
        |_cr| (),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 128.0,
            height: 128.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 128, 128).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf);

        cr.scale(128.0 / 48.0, 128.0 / 48.0);

        cr.rectangle(8.0, 8.0, 32.0, 32.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
        cr.fill();
    }

    let reference_surf = SharedImageSurface::new(reference_surf, SurfaceType::SRgb).unwrap();

    compare_to_surface(
        &output_surf,
        &reference_surf,
        "render_to_viewport_with_different_size",
    );
}

#[test]
fn render_to_offsetted_viewport() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <rect x="8" y="8" width="32" height="32" fill="blue"/>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(100, 100),
        |_cr| (),
        cairo::Rectangle {
            x: 10.0,
            y: 20.0,
            width: 48.0,
            height: 48.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf);

        cr.translate(10.0, 20.0);

        cr.rectangle(8.0, 8.0, 32.0, 32.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
        cr.fill();
    }

    let reference_surf = SharedImageSurface::new(reference_surf, SurfaceType::SRgb).unwrap();

    compare_to_surface(
        &output_surf,
        &reference_surf,
        "render_to_offseted_viewport",
    );
}

#[test]
fn render_to_viewport_with_transform() {
    let svg = load_svg(
        br#"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
  <g transform="translate(-10, -10)">
    <path fill="blue" d="M 18 18 l 32 0 l 0 32 l -32 0 z"/>
  </g>
</svg>
"#,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(100, 100),
        |cr| cr.translate(10.0, 20.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 48.0,
            height: 48.0,
        },
    )
    .unwrap();

    let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();

    {
        let cr = cairo::Context::new(&reference_surf);

        cr.translate(10.0, 20.0);
        cr.translate(-10.0, -10.0);

        cr.rectangle(18.0, 18.0, 32.0, 32.0);
        cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
        cr.fill();
    }

    let reference_surf = SharedImageSurface::new(reference_surf, SurfaceType::SRgb).unwrap();

    compare_to_surface(
        &output_surf,
        &reference_surf,
        "render_to_viewport_with_transform",
    );
}

#[test]
fn clip_on_transformed_viewport() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <defs>
    <clipPath id="one" clipPathUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.5"/>
    </clipPath>
  </defs>
  <g clip-path="url(#one)">
    <rect x="10" y="10" width="40" height="40" fill="blue"/>
    <rect x="50" y="50" width="40" height="40" fill="limegreen"/>
  </g>
</svg>
"##,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(200, 200),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    )
    .unwrap();

    compare_to_file(
        &output_surf,
        "clip_on_transformed_viewport",
        "clip-on-transformed-viewport-200x200.png",
    );
}

#[test]
fn mask_on_transformed_viewport() {
    let svg = load_svg(
        br##"<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  <defs>
    <mask id="one" maskContentUnits="objectBoundingBox">
      <circle cx="0.5" cy="0.5" r="0.5" fill="white"/>
    </mask>
  </defs>
  <g mask="url(#one)">
    <rect x="10" y="10" width="40" height="40" fill="blue"/>
    <rect x="50" y="50" width="40" height="40" fill="limegreen"/>
  </g>
</svg>
"##,
    );

    let output_surf = render_to_viewport(
        &svg,
        SurfaceSize(200, 200),
        |cr| cr.translate(50.0, 50.0),
        cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: 100.0,
            height: 100.0,
        },
    )
    .unwrap();

    compare_to_file(
        &output_surf,
        "mask_on_transformed_viewport",
        "mask-on-transformed-viewport-200x200.png",
    );
}
<|endoftext|>


<commit_before>/// Filters operating on numbers
use std::collections::HashMap;

#[cfg(feature = "builtins")]
use humansize::{file_size_opts, FileSize};
use serde_json::value::{to_value, Value};

use crate::errors::{Error, Result};

/// Returns a plural suffix if the value is not equal to ±1, or a singular
/// suffix otherwise. The plural suffix defaults to `s` and the singular suffix
/// defaults to the empty string (i.e nothing).
pub fn pluralize(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
    let num = try_get_value!("pluralize", "value", f64, value);

    let plural = match args.get("plural") {
        Some(val) => try_get_value!("pluralize", "plural", String, val),
        None => "s".to_string(),
    };

    let singular = match args.get("singular") {
        Some(val) => try_get_value!("pluralize", "singular", String, val),
        None => "".to_string(),
    };

    // English uses plural when it isn't one
    if (num.abs() - 1.).abs() > ::std::f64::EPSILON {
        Ok(to_value(&plural).unwrap())
    } else {
        Ok(to_value(&singular).unwrap())
    }
}

/// Returns a rounded number using the `method` arg and `precision` given.
/// `method` defaults to `common` which will round to the nearest number.
/// `ceil` and `floor` are also available as method.
/// `precision` defaults to `0`, meaning it will round to an integer
pub fn round(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
    let num = try_get_value!("round", "value", f64, value);
    let method = match args.get("method") {
        Some(val) => try_get_value!("round", "method", String, val),
        None => "common".to_string(),
    };
    let precision = match args.get("precision") {
        Some(val) => try_get_value!("round", "precision", i32, val),
        None => 0,
    };
    let multiplier = if precision == 0 { 1.0 } else { 10.0_f64.powi(precision) };

    match method.as_ref() {
        "common" => Ok(to_value((multiplier * num).round() / multiplier).unwrap()),
        "ceil" => Ok(to_value((multiplier * num).ceil() / multiplier).unwrap()),
        "floor" => Ok(to_value((multiplier * num).floor() / multiplier).unwrap()),
        _ => Err(Error::msg(format!(
            "Filter `round` received an incorrect value for arg `method`: got `{:?}`, \
             only common, ceil and floor are allowed",
            method
        ))),
    }
}

/// Returns a human-readable file size (i.e. '110 MB') from an integer
#[cfg(feature = "builtins")]
pub fn filesizeformat(value: &Value, _: &HashMap<String, Value>) -> Result<Value> {
    let num = try_get_value!("filesizeformat", "value", i64, value);
    num.file_size(file_size_opts::CONVENTIONAL)
        .or_else(|_| {
            Err(Error::msg(format!(
                "Filter `filesizeformat` was called on a negative number: {}",
                num
            )))
        })
        .map(to_value)
        .map(std::result::Result::unwrap)
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::value::to_value;
    use std::collections::HashMap;

    #[test]
    fn test_pluralize_single() {
        let result = pluralize(&to_value(1).unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("").unwrap());
    }

    #[test]
    fn test_pluralize_multiple() {
        let result = pluralize(&to_value(2).unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("s").unwrap());
    }

    #[test]
    fn test_pluralize_zero() {
        let result = pluralize(&to_value(0).unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("s").unwrap());
    }

    #[test]
    fn test_pluralize_multiple_custom_plural() {
        let mut args = HashMap::new();
        args.insert("plural".to_string(), to_value("es").unwrap());
        let result = pluralize(&to_value(2).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("es").unwrap());
    }

    #[test]
    fn test_pluralize_multiple_custom_singular() {
        let mut args = HashMap::new();
        args.insert("singular".to_string(), to_value("y").unwrap());
        let result = pluralize(&to_value(1).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("y").unwrap());
    }

    #[test]
    fn test_round_default() {
        let result = round(&to_value(2.1).unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(2.0).unwrap());
    }

    #[test]
    fn test_round_default_precision() {
        let mut args = HashMap::new();
        args.insert("precision".to_string(), to_value(2).unwrap());
        let result = round(&to_value(3.15159265359).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(3.15).unwrap());
    }

    #[test]
    fn test_round_ceil() {
        let mut args = HashMap::new();
        args.insert("method".to_string(), to_value("ceil").unwrap());
        let result = round(&to_value(2.1).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(3.0).unwrap());
    }

    #[test]
    fn test_round_ceil_precision() {
        let mut args = HashMap::new();
        args.insert("method".to_string(), to_value("ceil").unwrap());
        args.insert("precision".to_string(), to_value(1).unwrap());
        let result = round(&to_value(2.11).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(2.2).unwrap());
    }

    #[test]
    fn test_round_floor() {
        let mut args = HashMap::new();
        args.insert("method".to_string(), to_value("floor").unwrap());
        let result = round(&to_value(2.1).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(2.0).unwrap());
    }

    #[test]
    fn test_round_floor_precision() {
        let mut args = HashMap::new();
        args.insert("method".to_string(), to_value("floor").unwrap());
        args.insert("precision".to_string(), to_value(1).unwrap());
        let result = round(&to_value(2.91).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(2.9).unwrap());
    }

    #[cfg(feature = "builtins")]
    #[test]
    fn test_filesizeformat() {
        let args = HashMap::new();
        let result = filesizeformat(&to_value(123456789).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("117.74 MB").unwrap());
    }
}
<commit_msg>Use usize instead of i64<commit_after>/// Filters operating on numbers
use std::collections::HashMap;

#[cfg(feature = "builtins")]
use humansize::{file_size_opts, FileSize};
use serde_json::value::{to_value, Value};

use crate::errors::{Error, Result};

/// Returns a plural suffix if the value is not equal to ±1, or a singular
/// suffix otherwise. The plural suffix defaults to `s` and the singular suffix
/// defaults to the empty string (i.e nothing).
pub fn pluralize(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
    let num = try_get_value!("pluralize", "value", f64, value);

    let plural = match args.get("plural") {
        Some(val) => try_get_value!("pluralize", "plural", String, val),
        None => "s".to_string(),
    };

    let singular = match args.get("singular") {
        Some(val) => try_get_value!("pluralize", "singular", String, val),
        None => "".to_string(),
    };

    // English uses plural when it isn't one
    if (num.abs() - 1.).abs() > ::std::f64::EPSILON {
        Ok(to_value(&plural).unwrap())
    } else {
        Ok(to_value(&singular).unwrap())
    }
}

/// Returns a rounded number using the `method` arg and `precision` given.
/// `method` defaults to `common` which will round to the nearest number.
/// `ceil` and `floor` are also available as method.
/// `precision` defaults to `0`, meaning it will round to an integer
pub fn round(value: &Value, args: &HashMap<String, Value>) -> Result<Value> {
    let num = try_get_value!("round", "value", f64, value);
    let method = match args.get("method") {
        Some(val) => try_get_value!("round", "method", String, val),
        None => "common".to_string(),
    };
    let precision = match args.get("precision") {
        Some(val) => try_get_value!("round", "precision", i32, val),
        None => 0,
    };
    let multiplier = if precision == 0 { 1.0 } else { 10.0_f64.powi(precision) };

    match method.as_ref() {
        "common" => Ok(to_value((multiplier * num).round() / multiplier).unwrap()),
        "ceil" => Ok(to_value((multiplier * num).ceil() / multiplier).unwrap()),
        "floor" => Ok(to_value((multiplier * num).floor() / multiplier).unwrap()),
        _ => Err(Error::msg(format!(
            "Filter `round` received an incorrect value for arg `method`: got `{:?}`, \
             only common, ceil and floor are allowed",
            method
        ))),
    }
}

/// Returns a human-readable file size (i.e. '110 MB') from an integer
#[cfg(feature = "builtins")]
pub fn filesizeformat(value: &Value, _: &HashMap<String, Value>) -> Result<Value> {
    let num = try_get_value!("filesizeformat", "value", usize, value);
    num.file_size(file_size_opts::CONVENTIONAL)
        .or_else(|_| {
            Err(Error::msg(format!(
                "Filter `filesizeformat` was called on a negative number: {}",
                num
            )))
        })
        .map(to_value)
        .map(std::result::Result::unwrap)
}

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::value::to_value;
    use std::collections::HashMap;

    #[test]
    fn test_pluralize_single() {
        let result = pluralize(&to_value(1).unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("").unwrap());
    }

    #[test]
    fn test_pluralize_multiple() {
        let result = pluralize(&to_value(2).unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("s").unwrap());
    }

    #[test]
    fn test_pluralize_zero() {
        let result = pluralize(&to_value(0).unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("s").unwrap());
    }

    #[test]
    fn test_pluralize_multiple_custom_plural() {
        let mut args = HashMap::new();
        args.insert("plural".to_string(), to_value("es").unwrap());
        let result = pluralize(&to_value(2).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("es").unwrap());
    }

    #[test]
    fn test_pluralize_multiple_custom_singular() {
        let mut args = HashMap::new();
        args.insert("singular".to_string(), to_value("y").unwrap());
        let result = pluralize(&to_value(1).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("y").unwrap());
    }

    #[test]
    fn test_round_default() {
        let result = round(&to_value(2.1).unwrap(), &HashMap::new());
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(2.0).unwrap());
    }

    #[test]
    fn test_round_default_precision() {
        let mut args = HashMap::new();
        args.insert("precision".to_string(), to_value(2).unwrap());
        let result = round(&to_value(3.15159265359).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(3.15).unwrap());
    }

    #[test]
    fn test_round_ceil() {
        let mut args = HashMap::new();
        args.insert("method".to_string(), to_value("ceil").unwrap());
        let result = round(&to_value(2.1).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(3.0).unwrap());
    }

    #[test]
    fn test_round_ceil_precision() {
        let mut args = HashMap::new();
        args.insert("method".to_string(), to_value("ceil").unwrap());
        args.insert("precision".to_string(), to_value(1).unwrap());
        let result = round(&to_value(2.11).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(2.2).unwrap());
    }

    #[test]
    fn test_round_floor() {
        let mut args = HashMap::new();
        args.insert("method".to_string(), to_value("floor").unwrap());
        let result = round(&to_value(2.1).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(2.0).unwrap());
    }

    #[test]
    fn test_round_floor_precision() {
        let mut args = HashMap::new();
        args.insert("method".to_string(), to_value("floor").unwrap());
        args.insert("precision".to_string(), to_value(1).unwrap());
        let result = round(&to_value(2.91).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value(2.9).unwrap());
    }

    #[cfg(feature = "builtins")]
    #[test]
    fn test_filesizeformat() {
        let args = HashMap::new();
        let result = filesizeformat(&to_value(123456789).unwrap(), &args);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), to_value("117.74 MB").unwrap());
    }
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashSet};
use std::path::Path;

use core::PackageId;
use core::registry::PackageRegistry;
use core::{Resolve, SourceId, Package};
use core::resolver::Method;
use ops;
use util::config::Config;
use util::CargoResult;

pub struct UpdateOptions<'a> {
    pub config: &'a Config,
    pub to_update: &'a [String],
    pub precise: Option<&'a str>,
    pub aggressive: bool,
}

pub fn generate_lockfile(manifest_path: &Path, config: &Config)
                         -> CargoResult<()> {
    let package = try!(Package::for_path(manifest_path, config));
    let mut registry = PackageRegistry::new(config);
    let resolve = try!(ops::resolve_with_previous(&mut registry, &package,
                                                  Method::Everything,
                                                  None, None));
    try!(ops::write_pkg_lockfile(&package, &resolve));
    Ok(())
}

pub fn update_lockfile(manifest_path: &Path,
                       opts: &UpdateOptions) -> CargoResult<()> {

    if opts.aggressive && opts.precise.is_some() {
        bail!("cannot specify both aggressive and precise simultaneously")
    }

    let package = try!(Package::for_path(manifest_path, opts.config));

    let previous_resolve = match try!(ops::load_pkg_lockfile(&package, opts.config)) {
    	Some(resolve) => resolve,
	None => {
	     let _ = generate_lockfile(manifest_path, opts.config);
	     return Ok(());
	}
    };
    let mut registry = PackageRegistry::new(opts.config);
    let mut to_avoid = HashSet::new();

    if opts.to_update.is_empty() {
        to_avoid.extend(previous_resolve.iter());
    } else {
        let mut sources = Vec::new();
        for name in opts.to_update {
            let dep = try!(previous_resolve.query(name));
            if opts.aggressive {
                fill_with_deps(&previous_resolve, dep, &mut to_avoid,
                               &mut HashSet::new());
            } else {
                to_avoid.insert(dep);
                sources.push(match opts.precise {
                    Some(precise) => {
                        // TODO: see comment in `resolve.rs` as well, but this
                        //       seems like a pretty hokey reason to single out
                        //       the registry as well.
                        let precise = if dep.source_id().is_registry() {
                            format!("{}={}", dep.name(), precise)
                        } else {
                            precise.to_string()
                        };
                        dep.source_id().clone().with_precise(Some(precise))
                    }
                    None => {
                        dep.source_id().clone().with_precise(None)
                    }
                });
            }
        }
        try!(registry.add_sources(&sources));
    }

    let resolve = try!(ops::resolve_with_previous(&mut registry,
                                                  &package,
                                                  Method::Everything,
                                                  Some(&previous_resolve),
                                                  Some(&to_avoid)));

    // Summarize what is changing for the user.
    let print_change = |status: &str, msg: String| {
        opts.config.shell().status(status, msg)
    };
    for (removed, added) in compare_dependency_graphs(&previous_resolve, &resolve) {
        if removed.len() == 1 && added.len() == 1 {
            let msg = if removed[0].source_id().is_git() {
                format!("{} -> #{}", removed[0],
                        &added[0].source_id().precise().unwrap()[..8])
            } else {
                format!("{} -> v{}", removed[0], added[0].version())
            };
            try!(print_change("Updating", msg));
        } else {
            for package in removed.iter() {
                try!(print_change("Removing", format!("{}", package)));
            }
            for package in added.iter() {
                try!(print_change("Adding", format!("{}", package)));
            }
        }
    }

    try!(ops::write_pkg_lockfile(&package, &resolve));
    return Ok(());

    fn fill_with_deps<'a>(resolve: &'a Resolve, dep: &'a PackageId,
                          set: &mut HashSet<&'a PackageId>,
                          visited: &mut HashSet<&'a PackageId>) {
        if !visited.insert(dep) {
            return
        }
        set.insert(dep);
        if let Some(deps) =  resolve.deps(dep) {
            for dep in deps {
                fill_with_deps(resolve, dep, set, visited);
            }
        }
    }

    fn compare_dependency_graphs<'a>(previous_resolve: &'a Resolve,
                                     resolve: &'a Resolve) ->
                                     Vec<(Vec<&'a PackageId>, Vec<&'a PackageId>)> {
        fn key(dep: &PackageId) -> (&str, &SourceId) {
            (dep.name(), dep.source_id())
        }

        // Removes all package ids in `b` from `a`. Note that this is somewhat
        // more complicated because the equality for source ids does not take
        // precise versions into account (e.g. git shas), but we want to take
        // that into account here.
        fn vec_subtract<'a>(a: &[&'a PackageId],
                            b: &[&'a PackageId]) -> Vec<&'a PackageId> {
            a.iter().filter(|a| {
                // If this package id is not found in `b`, then it's definitely
                // in the subtracted set
                let i = match b.binary_search(a) {
                    Ok(i) => i,
                    Err(..) => return true,
                };

                // If we've found `a` in `b`, then we iterate over all instances
                // (we know `b` is sorted) and see if they all have different
                // precise versions. If so, then `a` isn't actually in `b` so
                // we'll let it through.
                //
                // Note that we only check this for non-registry sources,
                // however, as registries countain enough version information in
                // the package id to disambiguate
                if a.source_id().is_registry() {
                    return false
                }
                b[i..].iter().take_while(|b| a == b).all(|b| {
                    a.source_id().precise() != b.source_id().precise()
                })
            }).cloned().collect()
        }

        // Map (package name, package source) to (removed versions, added versions).
        let mut changes = BTreeMap::new();
        let empty = (Vec::new(), Vec::new());
        for dep in previous_resolve.iter() {
            changes.entry(key(dep)).or_insert(empty.clone()).0.push(dep);
        }
        for dep in resolve.iter() {
            changes.entry(key(dep)).or_insert(empty.clone()).1.push(dep);
        }

        for (_, v) in changes.iter_mut() {
            let (ref mut old, ref mut new) = *v;
            old.sort();
            new.sort();
            let removed = vec_subtract(old, new);
            let added = vec_subtract(new, old);
            *old = removed;
            *new = added;
        }
        debug!("{:#?}", changes);

        changes.into_iter().map(|(_, v)| v).collect()
    }
}
<commit_msg>remote unnecessary expression<commit_after>use std::collections::{BTreeMap, HashSet};
use std::path::Path;

use core::PackageId;
use core::registry::PackageRegistry;
use core::{Resolve, SourceId, Package};
use core::resolver::Method;
use ops;
use util::config::Config;
use util::CargoResult;

pub struct UpdateOptions<'a> {
    pub config: &'a Config,
    pub to_update: &'a [String],
    pub precise: Option<&'a str>,
    pub aggressive: bool,
}

pub fn generate_lockfile(manifest_path: &Path, config: &Config)
                         -> CargoResult<()> {
    let package = try!(Package::for_path(manifest_path, config));
    let mut registry = PackageRegistry::new(config);
    let resolve = try!(ops::resolve_with_previous(&mut registry, &package,
                                                  Method::Everything,
                                                  None, None));
    try!(ops::write_pkg_lockfile(&package, &resolve));
    Ok(())
}

pub fn update_lockfile(manifest_path: &Path,
                       opts: &UpdateOptions) -> CargoResult<()> {

    if opts.aggressive && opts.precise.is_some() {
        bail!("cannot specify both aggressive and precise simultaneously")
    }

    let package = try!(Package::for_path(manifest_path, opts.config));

    let previous_resolve = match try!(ops::load_pkg_lockfile(&package, opts.config)) {
    	Some(resolve) => resolve,
	None => {
	     return generate_lockfile(manifest_path, opts.config);
	}
    };
    let mut registry = PackageRegistry::new(opts.config);
    let mut to_avoid = HashSet::new();

    if opts.to_update.is_empty() {
        to_avoid.extend(previous_resolve.iter());
    } else {
        let mut sources = Vec::new();
        for name in opts.to_update {
            let dep = try!(previous_resolve.query(name));
            if opts.aggressive {
                fill_with_deps(&previous_resolve, dep, &mut to_avoid,
                               &mut HashSet::new());
            } else {
                to_avoid.insert(dep);
                sources.push(match opts.precise {
                    Some(precise) => {
                        // TODO: see comment in `resolve.rs` as well, but this
                        //       seems like a pretty hokey reason to single out
                        //       the registry as well.
                        let precise = if dep.source_id().is_registry() {
                            format!("{}={}", dep.name(), precise)
                        } else {
                            precise.to_string()
                        };
                        dep.source_id().clone().with_precise(Some(precise))
                    }
                    None => {
                        dep.source_id().clone().with_precise(None)
                    }
                });
            }
        }
        try!(registry.add_sources(&sources));
    }

    let resolve = try!(ops::resolve_with_previous(&mut registry,
                                                  &package,
                                                  Method::Everything,
                                                  Some(&previous_resolve),
                                                  Some(&to_avoid)));

    // Summarize what is changing for the user.
    let print_change = |status: &str, msg: String| {
        opts.config.shell().status(status, msg)
    };
    for (removed, added) in compare_dependency_graphs(&previous_resolve, &resolve) {
        if removed.len() == 1 && added.len() == 1 {
            let msg = if removed[0].source_id().is_git() {
                format!("{} -> #{}", removed[0],
                        &added[0].source_id().precise().unwrap()[..8])
            } else {
                format!("{} -> v{}", removed[0], added[0].version())
            };
            try!(print_change("Updating", msg));
        } else {
            for package in removed.iter() {
                try!(print_change("Removing", format!("{}", package)));
            }
            for package in added.iter() {
                try!(print_change("Adding", format!("{}", package)));
            }
        }
    }

    try!(ops::write_pkg_lockfile(&package, &resolve));
    return Ok(());

    fn fill_with_deps<'a>(resolve: &'a Resolve, dep: &'a PackageId,
                          set: &mut HashSet<&'a PackageId>,
                          visited: &mut HashSet<&'a PackageId>) {
        if !visited.insert(dep) {
            return
        }
        set.insert(dep);
        if let Some(deps) =  resolve.deps(dep) {
            for dep in deps {
                fill_with_deps(resolve, dep, set, visited);
            }
        }
    }

    fn compare_dependency_graphs<'a>(previous_resolve: &'a Resolve,
                                     resolve: &'a Resolve) ->
                                     Vec<(Vec<&'a PackageId>, Vec<&'a PackageId>)> {
        fn key(dep: &PackageId) -> (&str, &SourceId) {
            (dep.name(), dep.source_id())
        }

        // Removes all package ids in `b` from `a`. Note that this is somewhat
        // more complicated because the equality for source ids does not take
        // precise versions into account (e.g. git shas), but we want to take
        // that into account here.
        fn vec_subtract<'a>(a: &[&'a PackageId],
                            b: &[&'a PackageId]) -> Vec<&'a PackageId> {
            a.iter().filter(|a| {
                // If this package id is not found in `b`, then it's definitely
                // in the subtracted set
                let i = match b.binary_search(a) {
                    Ok(i) => i,
                    Err(..) => return true,
                };

                // If we've found `a` in `b`, then we iterate over all instances
                // (we know `b` is sorted) and see if they all have different
                // precise versions. If so, then `a` isn't actually in `b` so
                // we'll let it through.
                //
                // Note that we only check this for non-registry sources,
                // however, as registries countain enough version information in
                // the package id to disambiguate
                if a.source_id().is_registry() {
                    return false
                }
                b[i..].iter().take_while(|b| a == b).all(|b| {
                    a.source_id().precise() != b.source_id().precise()
                })
            }).cloned().collect()
        }

        // Map (package name, package source) to (removed versions, added versions).
        let mut changes = BTreeMap::new();
        let empty = (Vec::new(), Vec::new());
        for dep in previous_resolve.iter() {
            changes.entry(key(dep)).or_insert(empty.clone()).0.push(dep);
        }
        for dep in resolve.iter() {
            changes.entry(key(dep)).or_insert(empty.clone()).1.push(dep);
        }

        for (_, v) in changes.iter_mut() {
            let (ref mut old, ref mut new) = *v;
            old.sort();
            new.sort();
            let removed = vec_subtract(old, new);
            let added = vec_subtract(new, old);
            *old = removed;
            *new = added;
        }
        debug!("{:#?}", changes);

        changes.into_iter().map(|(_, v)| v).collect()
    }
}
<|endoftext|>


<commit_before>// examples/blinky.rs
//! Blinks an LED

#![feature(const_fn)]
#![feature(used)]
#![no_std]

// version = "0.2.0"
extern crate cortex_m_rt;

// version = "0.1.0"
#[macro_use]
extern crate cortex_m_rtfm as rtfm;
extern crate bluepill;
extern crate haldriver;

use bluepill::pin::{Pin, Mode};
use bluepill::frequency;
use bluepill::stm32f103xx::interrupt::{Tim3, Tim2};
use bluepill::stm32f103xx;
use bluepill::timer::{halTimer, Timer};
use rtfm::{Local, Resource, C2, P0, P1, P2, T0, T1, T2, TMax};
use haldriver::stepper::ulnXXXX::{Stepper, halStepper, Direction};
use core::cell::Cell;

// stepper update ticks, maybe be able to go faster on 5V
const TICKS: u32 = 64_000;
// controller update ticks still need to tweak for a good value
const TICKS2: u32 = 128_000;

// XPATTERN and YPATTERN are the path for the x and y axis
const XPATTERN: [i32; 5] = [4096, -2000, 500, -500, 200];
const YPATTERN: [i32; 5] = [1000, -2000, 1500, -500, 200];

struct stepCount {
    steps: Cell<i32>,
}

impl stepCount {
    const fn new() -> Self {
        stepCount {steps: Cell::new(0)}
    }
}

// RESOURCES
peripherals!(stm32f103xx, {
    GPIOA: Peripheral {
        register_block: Gpioa,
        ceiling: C2,
    },
    RCC: Peripheral {
        register_block: Rcc,
        ceiling: C0,
    },
    TIM2: Peripheral {
        register_block: Tim2,
        ceiling: C1,
    },
    TIM3: Peripheral {
        register_block: Tim3,
        ceiling: C2,
    },
    FLASH: Peripheral {
        register_block: Flash,
        ceiling: C0,
    },
});

// XSTEPS and YSTEPS hold the amount of steps for the current move
static XSTEPS: Resource<stepCount, C2> = Resource::new(stepCount::new());
static YSTEPS: Resource<stepCount, C2> = Resource::new(stepCount::new());

// INITIALIZATION PHASE
fn init(ref priority: P0, threshold: &TMax) {
    let gpioa = GPIOA.access(priority, threshold);
    let rcc = RCC.access(priority, threshold);
    let tim3 = TIM3.access(priority, threshold);
    let tim2 = TIM2.access(priority, threshold);
    let flash = FLASH.access(priority, threshold);
    let timer = Timer::new(&**tim3);
    let timer2 = Timer::new(&**tim2);
    // stepper pins
    let in1 = Pin{pin: 1, port: &**gpioa};
    let in2 = Pin{pin: 2, port: &**gpioa};
    let in3 = Pin{pin: 3, port: &**gpioa};
    let in4 = Pin{pin: 4, port: &**gpioa};
    let in5 = Pin{pin: 8, port: &**gpioa};
    let in6 = Pin{pin: 9, port: &**gpioa};
    let in7 = Pin{pin: 10, port: &**gpioa};
    let in8 = Pin{pin: 11, port: &**gpioa};

    // set clock to 32Mhz
    frequency::init(&rcc, &flash, frequency::Speed::S32Mhz);

    // configure pins for output
    in1.init(&rcc, Mode::OUTPUT);
    in2.init(&rcc, Mode::OUTPUT);
    in3.init(&rcc, Mode::OUTPUT);
    in4.init(&rcc, Mode::OUTPUT);
    in5.init(&rcc, Mode::OUTPUT);
    in6.init(&rcc, Mode::OUTPUT);
    in7.init(&rcc, Mode::OUTPUT);
    in8.init(&rcc, Mode::OUTPUT);

    // Configure TIM3 for periodic update events
    timer.init(&rcc, TICKS);

    // Configure TIM2 for periodic update events
    timer2.init(&rcc, TICKS2);

    // Start the timer
    timer.resume();
    timer2.resume();
}

// IDLE LOOP
fn idle(_priority: P0, _threshold: T0) -> ! {
    // Sleep
    loop {
        rtfm::wfi();
    }
}

// TASKS
tasks!(stm32f103xx, {
    stepper: Task {
        interrupt: Tim3,
        priority: P2,
        enabled: true,
    },
    controller: Task {
        interrupt: Tim2,
        priority: P1,
        enabled: true,
    },
});

fn stepper(mut task: Tim3, ref priority: P2, ref threshold: T2) {
    // Task local data
    // have to track step manually since you can't persist
    // a stepper between calls
    static XINDEX: Local<u8, Tim3> = Local::new(0);
    static YINDEX: Local<u8, Tim3> = Local::new(0);

    let tim3 = TIM3.access(priority, threshold);
    let timer = Timer{timer: &**tim3};
    let gpioa = GPIOA.access(priority, threshold);
    let in1 = Pin{pin: 1, port: &**gpioa};
    let in2 = Pin{pin: 2, port: &**gpioa};
    let in3 = Pin{pin: 3, port: &**gpioa};
    let in4 = Pin{pin: 4, port: &**gpioa};
    let in5 = Pin{pin: 8, port: &**gpioa};
    let in6 = Pin{pin: 9, port: &**gpioa};
    let in7 = Pin{pin: 10, port: &**gpioa};
    let in8 = Pin{pin: 11, port: &**gpioa};

    if timer.clear_update_flag().is_ok() {
        let xsteps = XSTEPS.access(priority, threshold);
        // if there are any current x steps to take
        if xsteps.steps.get() != 0 {
            let xindex = XINDEX.borrow_mut(&mut task);

            let mut stepper = Stepper{direction: Direction::RIGHT,
                index: *xindex,
                pin1: &in1,
                pin2: &in2,
                pin3: &in3,
                pin4: &in4,};

            stepper.step();

            // take one xstep
            if xsteps.steps.get() > 0 {
                *xindex = if *xindex < 7 { *xindex + 1 } else { 0 };
                xsteps.steps.set(xsteps.steps.get() - 1);
            } else {
                *xindex = if *xindex > 0 { *xindex - 1 } else { 7 };
                xsteps.steps.set(xsteps.steps.get() + 1);
            }
        }

        let ysteps = YSTEPS.access(priority, threshold);
        //if there are any ysteps to take
        if ysteps.steps.get() != 0 {
            let yindex = YINDEX.borrow_mut(&mut task);

            let mut stepper = Stepper{direction: Direction::RIGHT,
                index: *yindex,
                pin1: &in5,
                pin2: &in6,
                pin3: &in7,
                pin4: &in8,};

            stepper.step();

            // take one ystep
            if ysteps.steps.get() > 0 {
                *yindex = if *yindex < 7 { *yindex + 1 } else { 0 };
                ysteps.steps.set(ysteps.steps.get() - 1);
            } else {
                *yindex = if *yindex > 0 { *yindex -1 } else { 7 };
                ysteps.steps.set(ysteps.steps.get() + 1);
            }
        }
    } else {
        // Only reachable through `rtfm::request(periodic)`
        #[cfg(debug_assertion)]
        unreachable!()
    }
}

// send steps to the stepper task, eventually add some path planning and
// input for movement from serial
fn controller(mut task: Tim2, ref priority: P1, ref threshold: T1) {
    static XINDEX: Local<u8, Tim2> = Local::new(0);
    static YINDEX: Local<u8, Tim2> = Local::new(0);

    let tim2 = TIM2.access(priority, threshold);
    let timer = Timer{timer: &**tim2};

    if timer.clear_update_flag().is_ok() {

        // make sure current move is completed before sending next move
        // blocks on both x and y
        while threshold.raise(
                &XSTEPS, |threshold| {
                    let xsteps = XSTEPS.access(priority, threshold);
                    xsteps.steps.get()
                }
        ) != 0 {}
        while threshold.raise(
                &YSTEPS, |threshold| {
                    let ysteps = YSTEPS.access(priority, threshold);
                    ysteps.steps.get()
                }
        ) != 0 {}
        {
            // send the next x move, currently x and y are the same length
            // need to add checks when this becomes more dynamic
            let xindex = XINDEX.borrow_mut(&mut task);
            threshold.raise(
                &XSTEPS, |threshold| {
                    let xsteps = XSTEPS.access(priority, threshold);
                    xsteps.steps.set(XPATTERN[*xindex as usize]);
                }
            );
            *xindex = if *xindex < XPATTERN.len() as u8 - 1 { *xindex + 1 } else { 0 };
        }
        // send the next y move, currently x and y are the same length
        // need to add checks when this becomes more dynamic
        let yindex = YINDEX.borrow_mut(&mut task);
        threshold.raise(
            &YSTEPS, |threshold| {
                let ysteps = YSTEPS.access(priority, threshold);
                ysteps.steps.set(YPATTERN[*yindex as usize]);
            }
        );
        *yindex = if *yindex < YPATTERN.len() as u8 - 1 { *yindex + 1 } else { 0 };
    } else {
        // Only reachable through `rtfm::request(periodic)`
        #[cfg(debug_assertion)]
        unreachable!()
    }
}<commit_msg>change x and y steps to be spread out evenly<commit_after>// examples/blinky.rs
//! Blinks an LED

#![feature(const_fn)]
#![feature(used)]
#![no_std]

// version = "0.2.0"
extern crate cortex_m_rt;

// version = "0.1.0"
#[macro_use]
extern crate cortex_m_rtfm as rtfm;
extern crate bluepill;
extern crate haldriver;

use bluepill::pin::{Pin, Mode};
use bluepill::frequency;
use bluepill::stm32f103xx::interrupt::{Tim3, Tim2};
use bluepill::stm32f103xx;
use bluepill::timer::{halTimer, Timer};
use rtfm::{Local, Resource, C2, P0, P1, P2, T0, T1, T2, TMax};
use haldriver::stepper::ulnXXXX::{Stepper, halStepper, Direction};
use core::cell::Cell;

// stepper update ticks, 500 pulse/sec is around the max
const TICKS: u32 = 144_000;
// controller update ticks still need to tweak for a good value
const TICKS2: u32 = 1_000_000;

// XPATTERN and YPATTERN are the path for the x and y axis
const XPATTERN: [i32; 5] = [4096, -2000, 500, -500, 200];
const YPATTERN: [i32; 5] = [1000, -2000, 1500, -500, 200];

fn gcd(x: i32, y: i32) -> i32 {
    let mut x = x;
    let mut y = y;
    while y != 0 {
        let t = y;
        y = x % y;
        x = t;
    }
    x
}

struct stepCount {
    steps: Cell<i32>,
}

impl stepCount {
    const fn new() -> Self {
        stepCount {steps: Cell::new(0)}
    }
}

// RESOURCES
peripherals!(stm32f103xx, {
    GPIOA: Peripheral {
        register_block: Gpioa,
        ceiling: C2,
    },
    RCC: Peripheral {
        register_block: Rcc,
        ceiling: C0,
    },
    TIM2: Peripheral {
        register_block: Tim2,
        ceiling: C1,
    },
    TIM3: Peripheral {
        register_block: Tim3,
        ceiling: C2,
    },
    FLASH: Peripheral {
        register_block: Flash,
        ceiling: C0,
    },
});

// XSTEPS and YSTEPS hold the amount of steps for the current move
static XSTEPS: Resource<stepCount, C2> = Resource::new(stepCount::new());
static YSTEPS: Resource<stepCount, C2> = Resource::new(stepCount::new());

// INITIALIZATION PHASE
fn init(ref priority: P0, threshold: &TMax) {
    let gpioa = GPIOA.access(priority, threshold);
    let rcc = RCC.access(priority, threshold);
    let tim3 = TIM3.access(priority, threshold);
    let tim2 = TIM2.access(priority, threshold);
    let flash = FLASH.access(priority, threshold);
    let timer = Timer::new(&**tim3);
    let timer2 = Timer::new(&**tim2);
    // stepper pins
    let in1 = Pin{pin: 1, port: &**gpioa};
    let in2 = Pin{pin: 2, port: &**gpioa};
    let in3 = Pin{pin: 3, port: &**gpioa};
    let in4 = Pin{pin: 4, port: &**gpioa};
    let in5 = Pin{pin: 8, port: &**gpioa};
    let in6 = Pin{pin: 9, port: &**gpioa};
    let in7 = Pin{pin: 10, port: &**gpioa};
    let in8 = Pin{pin: 11, port: &**gpioa};

    // set clock to 32Mhz
    frequency::init(&rcc, &flash, frequency::Speed::S32Mhz);

    // configure pins for output
    in1.init(&rcc, Mode::OUTPUT);
    in2.init(&rcc, Mode::OUTPUT);
    in3.init(&rcc, Mode::OUTPUT);
    in4.init(&rcc, Mode::OUTPUT);
    in5.init(&rcc, Mode::OUTPUT);
    in6.init(&rcc, Mode::OUTPUT);
    in7.init(&rcc, Mode::OUTPUT);
    in8.init(&rcc, Mode::OUTPUT);

    // Configure TIM3 for periodic update events
    timer.init(&rcc, TICKS);

    // Configure TIM2 for periodic update events
    timer2.init(&rcc, TICKS2);

    // Start the timer
    timer.resume();
    timer2.resume();
}

// IDLE LOOP
fn idle(_priority: P0, _threshold: T0) -> ! {
    // Sleep
    loop {
        rtfm::wfi();
    }
}

// TASKS
tasks!(stm32f103xx, {
    stepper: Task {
        interrupt: Tim3,
        priority: P2,
        enabled: true,
    },
    controller: Task {
        interrupt: Tim2,
        priority: P1,
        enabled: true,
    },
});

fn stepper(mut task: Tim3, ref priority: P2, ref threshold: T2) {
    // Task local data
    // have to track step manually since you can't persist
    // a stepper between calls
    static XINDEX: Local<u8, Tim3> = Local::new(0);
    static YINDEX: Local<u8, Tim3> = Local::new(0);

    let tim3 = TIM3.access(priority, threshold);
    let timer = Timer{timer: &**tim3};
    let gpioa = GPIOA.access(priority, threshold);
    let in1 = Pin{pin: 1, port: &**gpioa};
    let in2 = Pin{pin: 2, port: &**gpioa};
    let in3 = Pin{pin: 3, port: &**gpioa};
    let in4 = Pin{pin: 4, port: &**gpioa};
    let in5 = Pin{pin: 8, port: &**gpioa};
    let in6 = Pin{pin: 9, port: &**gpioa};
    let in7 = Pin{pin: 10, port: &**gpioa};
    let in8 = Pin{pin: 11, port: &**gpioa};

    if timer.clear_update_flag().is_ok() {
        let xsteps = XSTEPS.access(priority, threshold);
        // if there are any current x steps to take
        if xsteps.steps.get() != 0 {
            let xindex = XINDEX.borrow_mut(&mut task);

            let mut stepper = Stepper{direction: Direction::RIGHT,
                index: *xindex,
                pin1: &in1,
                pin2: &in2,
                pin3: &in3,
                pin4: &in4,};

            stepper.step();

            // take one xstep
            if xsteps.steps.get() > 0 {
                *xindex = if *xindex < 7 { *xindex + 1 } else { 0 };
                xsteps.steps.set(xsteps.steps.get() - 1);
            } else {
                *xindex = if *xindex > 0 { *xindex - 1 } else { 7 };
                xsteps.steps.set(xsteps.steps.get() + 1);
            }
        }

        let ysteps = YSTEPS.access(priority, threshold);
        //if there are any ysteps to take
        if ysteps.steps.get() != 0 {
            let yindex = YINDEX.borrow_mut(&mut task);

            let mut stepper = Stepper{direction: Direction::RIGHT,
                index: *yindex,
                pin1: &in5,
                pin2: &in6,
                pin3: &in7,
                pin4: &in8,};

            stepper.step();

            // take one ystep
            if ysteps.steps.get() > 0 {
                *yindex = if *yindex < 7 { *yindex + 1 } else { 0 };
                ysteps.steps.set(ysteps.steps.get() - 1);
            } else {
                *yindex = if *yindex > 0 { *yindex -1 } else { 7 };
                ysteps.steps.set(ysteps.steps.get() + 1);
            }
        }
    } else {
        // Only reachable through `rtfm::request(periodic)`
        #[cfg(debug_assertion)]
        unreachable!()
    }
}

// send steps to the stepper task, eventually add some path planning and
// input for movement from serial
fn controller(mut task: Tim2, ref priority: P1, ref threshold: T1) {
    static XINDEX: Local<u8, Tim2> = Local::new(0);
    static YINDEX: Local<u8, Tim2> = Local::new(0);

    let tim2 = TIM2.access(priority, threshold);
    let timer = Timer{timer: &**tim2};

    if timer.clear_update_flag().is_ok() {
        // get current movement
        let xmove = XPATTERN[*XINDEX.borrow(&task) as usize];
        let ymove = YPATTERN[*YINDEX.borrow(&task) as usize];

        // figure out step size
        // probably need to add a check if either are 0
        let gcd = gcd(xmove, ymove);
        let xmove = xmove / gcd;
        let ymove = ymove / gcd;
        for _ in 0..gcd{
            // make sure current move is completed before sending next move
            // blocks on both x and y
            while threshold.raise(
                    &XSTEPS, |threshold| {
                        let xsteps = XSTEPS.access(priority, threshold);
                        xsteps.steps.get()
                    }
            ) != 0 {}
            while threshold.raise(
                    &YSTEPS, |threshold| {
                        let ysteps = YSTEPS.access(priority, threshold);
                        ysteps.steps.get()
                    }
            ) != 0 {}
            // send the next x move
            threshold.raise(
                &XSTEPS, |threshold| {
                    let xsteps = XSTEPS.access(priority, threshold);
                    xsteps.steps.set(xmove);
                }
            );
            // send the next y move
            threshold.raise(
                &YSTEPS, |threshold| {
                    let ysteps = YSTEPS.access(priority, threshold);
                    ysteps.steps.set(ymove);
                }
            );
        }
        // need to get mutable x index in it's own block due
        // to borrow checker being overly strick with borrow_mut
        {
            let xindex = XINDEX.borrow_mut(&mut task);
            *xindex = if *xindex < XPATTERN.len() as u8 - 1 { *xindex + 1 } else { 0 };
        }
        let yindex = YINDEX.borrow_mut(&mut task);
        *yindex = if *yindex < YPATTERN.len() as u8 - 1 { *yindex + 1 } else { 0 };
    } else {
        // Only reachable through `rtfm::request(periodic)`
        #[cfg(debug_assertion)]
        unreachable!()
    }
}<|endoftext|>


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

// Handles invoking external binaries.
// This module assumes that, for a given machine, there is only one place
// where the desired executable might be installed. It expects the engine
// to identify that place at its initialization by invoking verify_binaries(),
// and to exit immediately if verify_binaries() return an error. If this
// protocol is followed then when any command is executed the unique absolute
// path of the binary for this machine will already have been identified.
// However stratisd may run for a while and it is possible for the binary
// to be caused to be uninstalled while stratisd is being run. Therefore,
// the existence of the file is checked before the command is invoked, and
// an explicit error is returned if the executable can not be found.

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::process::Command;

use uuid::Uuid;

use stratis::{StratisError, StratisResult};

/// Find the binary with the given name by looking in likely locations.
/// Return None if no binary was found.
/// Search an explicit list of directories rather than the user's PATH
/// environment variable. stratisd may be running when there is no PATH
/// variable set.
fn find_binary(name: &str) -> Option<PathBuf> {
    ["/usr/sbin", "/sbin", "/usr/bin", "/bin"]
        .iter()
        .map(|pre| [pre, name].iter().collect::<PathBuf>())
        .find(|path| path.exists())
}

// These are the external binaries that stratisd relies on.
// Any change in this list requires a corresponding change to BINARIES,
// and vice-versa.
const MKFS_XFS: &str = "mkfs.xfs";
const THIN_CHECK: &str = "thin_check";
const THIN_REPAIR: &str = "thin_repair";
const UDEVADM: &str = "udevadm";
const XFS_DB: &str = "xfs_db";
const XFS_GROWFS: &str = "xfs_growfs";

lazy_static! {
    static ref BINARIES: HashMap<String, Option<PathBuf>> = [
        (MKFS_XFS.to_string(), find_binary(MKFS_XFS)),
        (THIN_CHECK.to_string(), find_binary(THIN_CHECK)),
        (THIN_REPAIR.to_string(), find_binary(THIN_REPAIR)),
        (UDEVADM.to_string(), find_binary(UDEVADM)),
        (XFS_DB.to_string(), find_binary(XFS_DB)),
        (XFS_GROWFS.to_string(), find_binary(XFS_GROWFS)),
    ].iter()
        .cloned()
        .collect();
}

/// Verify that all binaries that the engine might invoke are available at some
/// path. Return an error if any are missing. Required to be called on engine
/// initialization.
pub fn verify_binaries() -> StratisResult<()> {
    match BINARIES.iter().find(|&(_, ref path)| path.is_none()) {
        None => Ok(()),
        Some((ref name, _)) => Err(StratisError::Error(format!(
            "Unable to find absolute path for \"{}\"",
            name
        ))),
    }
}

/// Invoke the specified command. Return an error if invoking the command
/// fails or if the command itself fails.
fn execute_cmd(cmd: &mut Command) -> StratisResult<()> {
    match cmd.output() {
        Err(err) => Err(StratisError::Error(format!(
            "Failed to execute command {:?}, err: {:?}",
            cmd, err
        ))),
        Ok(result) => {
            if result.status.success() {
                Ok(())
            } else {
                let std_out_txt = String::from_utf8_lossy(&result.stdout);
                let std_err_txt = String::from_utf8_lossy(&result.stderr);
                let err_msg = format!(
                    "Command failed: cmd: {:?}, stdout: {} stderr: {}",
                    cmd, std_out_txt, std_err_txt
                );
                Err(StratisError::Error(err_msg))
            }
        }
    }
}

/// Get an absolute path for the executable with the given name.
/// Precondition: verify_binaries() has already been invoked.
fn get_executable(name: &str) -> &Path {
    BINARIES
        .get(name)
        .expect("name arguments are all constants defined with BINARIES, lookup can not fail")
        .as_ref()
        .expect("verify_binaries() was previously called and returned no error")
}

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path, uuid: Uuid) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(MKFS_XFS).as_os_str())
            .arg("-f")
            .arg("-q")
            .arg(&devnode)
            .arg("-m")
            .arg(format!("uuid={}", uuid)),
    )
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(XFS_GROWFS).as_os_str())
            .arg(mount_point)
            .arg("-d"),
    )
}

/// Set a new UUID for filesystem on the devnode.
pub fn set_uuid(devnode: &Path, uuid: Uuid) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(XFS_DB).as_os_str())
            .arg("-x")
            .arg(format!("-c uuid {}", uuid))
            .arg(&devnode),
    )
}

/// Call thin_check on a thinpool
pub fn thin_check(devnode: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(THIN_CHECK).as_os_str())
            .arg("-q")
            .arg(devnode),
    )
}

/// Call thin_repair on a thinpool
pub fn thin_repair(meta_dev: &Path, new_meta_dev: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(THIN_REPAIR).as_os_str())
            .arg("-i")
            .arg(meta_dev)
            .arg("-o")
            .arg(new_meta_dev),
    )
}

/// Call udevadm settle
pub fn udev_settle() -> StratisResult<()> {
    execute_cmd(Command::new(get_executable(UDEVADM).as_os_str()).arg("settle"))
}

#[cfg(test)]
pub fn create_ext3_fs(devnode: &Path) -> StratisResult<()> {
    execute_cmd(Command::new("mkfs.ext3").arg(&devnode))
}

#[cfg(test)]
pub fn xfs_repair(devnode: &Path) -> StratisResult<()> {
    execute_cmd(Command::new("xfs_repair").arg("-n").arg(&devnode))
}
<commit_msg>Address issue with real_test_fail_single_signature<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Handles invoking external binaries.
// This module assumes that, for a given machine, there is only one place
// where the desired executable might be installed. It expects the engine
// to identify that place at its initialization by invoking verify_binaries(),
// and to exit immediately if verify_binaries() return an error. If this
// protocol is followed then when any command is executed the unique absolute
// path of the binary for this machine will already have been identified.
// However stratisd may run for a while and it is possible for the binary
// to be caused to be uninstalled while stratisd is being run. Therefore,
// the existence of the file is checked before the command is invoked, and
// an explicit error is returned if the executable can not be found.

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::process::Command;

use uuid::Uuid;

use stratis::{StratisError, StratisResult};

/// Find the binary with the given name by looking in likely locations.
/// Return None if no binary was found.
/// Search an explicit list of directories rather than the user's PATH
/// environment variable. stratisd may be running when there is no PATH
/// variable set.
fn find_binary(name: &str) -> Option<PathBuf> {
    ["/usr/sbin", "/sbin", "/usr/bin", "/bin"]
        .iter()
        .map(|pre| [pre, name].iter().collect::<PathBuf>())
        .find(|path| path.exists())
}

// These are the external binaries that stratisd relies on.
// Any change in this list requires a corresponding change to BINARIES,
// and vice-versa.
const MKFS_XFS: &str = "mkfs.xfs";
const THIN_CHECK: &str = "thin_check";
const THIN_REPAIR: &str = "thin_repair";
const UDEVADM: &str = "udevadm";
const XFS_DB: &str = "xfs_db";
const XFS_GROWFS: &str = "xfs_growfs";

lazy_static! {
    static ref BINARIES: HashMap<String, Option<PathBuf>> = [
        (MKFS_XFS.to_string(), find_binary(MKFS_XFS)),
        (THIN_CHECK.to_string(), find_binary(THIN_CHECK)),
        (THIN_REPAIR.to_string(), find_binary(THIN_REPAIR)),
        (UDEVADM.to_string(), find_binary(UDEVADM)),
        (XFS_DB.to_string(), find_binary(XFS_DB)),
        (XFS_GROWFS.to_string(), find_binary(XFS_GROWFS)),
    ].iter()
        .cloned()
        .collect();
}

/// Verify that all binaries that the engine might invoke are available at some
/// path. Return an error if any are missing. Required to be called on engine
/// initialization.
pub fn verify_binaries() -> StratisResult<()> {
    match BINARIES.iter().find(|&(_, ref path)| path.is_none()) {
        None => Ok(()),
        Some((ref name, _)) => Err(StratisError::Error(format!(
            "Unable to find absolute path for \"{}\"",
            name
        ))),
    }
}

/// Invoke the specified command. Return an error if invoking the command
/// fails or if the command itself fails.
fn execute_cmd(cmd: &mut Command) -> StratisResult<()> {
    match cmd.output() {
        Err(err) => Err(StratisError::Error(format!(
            "Failed to execute command {:?}, err: {:?}",
            cmd, err
        ))),
        Ok(result) => {
            if result.status.success() {
                Ok(())
            } else {
                let std_out_txt = String::from_utf8_lossy(&result.stdout);
                let std_err_txt = String::from_utf8_lossy(&result.stderr);
                let err_msg = format!(
                    "Command failed: cmd: {:?}, stdout: {} stderr: {}",
                    cmd, std_out_txt, std_err_txt
                );
                Err(StratisError::Error(err_msg))
            }
        }
    }
}

/// Get an absolute path for the executable with the given name.
/// Precondition: verify_binaries() has already been invoked.
fn get_executable(name: &str) -> &Path {
    BINARIES
        .get(name)
        .expect("name arguments are all constants defined with BINARIES, lookup can not fail")
        .as_ref()
        .expect("verify_binaries() was previously called and returned no error")
}

/// Create a filesystem on devnode.
pub fn create_fs(devnode: &Path, uuid: Uuid) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(MKFS_XFS).as_os_str())
            .arg("-f")
            .arg("-q")
            .arg(&devnode)
            .arg("-m")
            .arg(format!("uuid={}", uuid)),
    )
}

/// Use the xfs_growfs command to expand a filesystem mounted at the given
/// mount point.
pub fn xfs_growfs(mount_point: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(XFS_GROWFS).as_os_str())
            .arg(mount_point)
            .arg("-d"),
    )
}

/// Set a new UUID for filesystem on the devnode.
pub fn set_uuid(devnode: &Path, uuid: Uuid) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(XFS_DB).as_os_str())
            .arg("-x")
            .arg(format!("-c uuid {}", uuid))
            .arg(&devnode),
    )
}

/// Call thin_check on a thinpool
pub fn thin_check(devnode: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(THIN_CHECK).as_os_str())
            .arg("-q")
            .arg(devnode),
    )
}

/// Call thin_repair on a thinpool
pub fn thin_repair(meta_dev: &Path, new_meta_dev: &Path) -> StratisResult<()> {
    execute_cmd(
        Command::new(get_executable(THIN_REPAIR).as_os_str())
            .arg("-i")
            .arg(meta_dev)
            .arg("-o")
            .arg(new_meta_dev),
    )
}

/// Call udevadm settle
pub fn udev_settle() -> StratisResult<()> {
    execute_cmd(Command::new(get_executable(UDEVADM).as_os_str()).arg("settle"))
}

#[cfg(test)]
pub fn create_ext3_fs(devnode: &Path) -> StratisResult<()> {
    execute_cmd(Command::new("wipefs").arg("-a").arg(&devnode))?;
    execute_cmd(Command::new("mkfs.ext3").arg(&devnode))
}

#[cfg(test)]
pub fn xfs_repair(devnode: &Path) -> StratisResult<()> {
    execute_cmd(Command::new("xfs_repair").arg("-n").arg(&devnode))
}
<|endoftext|>