<commit_before>use sodiumoxide::crypto::sign;
use std::borrow::Cow;

use super::stack::*;
use super::*;
use crate::crypto::PublicKey;
use crate::tx::TxVariant;

macro_rules! map_err_type {
    ($self:expr, $var:expr) => {
        $var.map_err(|e| $self.new_err(e))
    };
}

pub struct ScriptEngine<'a> {
    script: Cow<'a, Script>,
    tx: Cow<'a, TxVariant>,
    pos: usize,
    stack: Stack,
}

impl<'a> ScriptEngine<'a> {
    pub fn checked_new<T, S>(tx: T, script: S) -> Option<Self>
    where
        T: Into<Cow<'a, TxVariant>>,
        S: Into<Cow<'a, Script>>,
    {
        let script = script.into();
        let tx = tx.into();
        if script.len() > MAX_BYTE_SIZE {
            return None;
        }
        Some(Self {
            script,
            tx,
            pos: 0,
            stack: Stack::new(),
        })
    }

    pub fn eval(&mut self) -> Result<bool, EvalErr> {
        self.pos = 0;
        let mut if_marker = 0;
        let mut ignore_else = false;
        while let Some(op) = self.consume_op()? {
            match op {
                // Control
                OpFrame::OpIf => {
                    if_marker += 1;
                    ignore_else = map_err_type!(self, self.stack.pop_bool())?;
                    if ignore_else {
                        continue;
                    }
                    let req_if_marker = if_marker;
                    self.consume_op_until(|op| {
                        if op == OpFrame::OpIf {
                            if_marker += 1;
                            false
                        } else if op == OpFrame::OpElse {
                            if_marker == req_if_marker
                        } else if op == OpFrame::OpEndIf {
                            let do_break = if_marker == req_if_marker;
                            if_marker -= 1;
                            do_break
                        } else {
                            false
                        }
                    })?;
                }
                OpFrame::OpElse => {
                    if !ignore_else {
                        continue;
                    }
                    let req_if_marker = if_marker;
                    self.consume_op_until(|op| {
                        if op == OpFrame::OpIf {
                            if_marker += 1;
                            false
                        } else if op == OpFrame::OpElse {
                            if_marker == req_if_marker
                        } else if op == OpFrame::OpEndIf {
                            let do_break = if_marker == req_if_marker;
                            if_marker -= 1;
                            do_break
                        } else {
                            false
                        }
                    })?;
                }
                OpFrame::OpEndIf => {
                    if_marker -= 1;
                }
                OpFrame::OpReturn => {
                    if_marker = 0;
                    break;
                }
                // Crypto
                OpFrame::OpCheckSig => {
                    let key = map_err_type!(self, self.stack.pop_pubkey())?;
                    if self.tx.signature_pairs.len() != 1 {
                        map_err_type!(self, self.stack.push(false))?;
                        continue;
                    }
                    let mut buf = Vec::with_capacity(4096);
                    self.tx.encode(&mut buf);
                    let success = key.verify(&buf, &self.tx.signature_pairs[0].signature);
                    map_err_type!(self, self.stack.push(success))?;
                }
                // Handle push ops
                _ => {
                    map_err_type!(self, self.stack.push(op))?;
                }
            }
        }

        if if_marker > 0 {
            return Err(self.new_err(EvalErrType::UnexpectedEOF));
        }

        // Scripts must return true or false
        map_err_type!(self, self.stack.pop_bool())
    }

    fn consume_op_until<F>(&mut self, mut filter: F) -> Result<(), EvalErr>
    where
        F: FnMut(OpFrame) -> bool,
    {
        loop {
            match self.consume_op()? {
                Some(op) => {
                    if filter(op) {
                        break;
                    }
                }
                None => return Err(self.new_err(EvalErrType::UnexpectedEOF)),
            }
        }

        Ok(())
    }

    fn consume_op(&mut self) -> Result<Option<OpFrame>, EvalErr> {
        if self.pos == self.script.len() {
            return Ok(None);
        }
        let byte = self.script[self.pos];
        self.pos += 1;

        match byte {
            o if o == Operand::PushFalse as u8 => Ok(Some(OpFrame::False)),
            o if o == Operand::PushTrue as u8 => Ok(Some(OpFrame::True)),
            o if o == Operand::PushPubKey as u8 => {
                let slice = self.pos..self.pos + sign::PUBLICKEYBYTES;
                let key = match self.script.get(slice) {
                    Some(slice) => {
                        self.pos += sign::PUBLICKEYBYTES;
                        PublicKey::from_slice(slice).unwrap()
                    }
                    None => {
                        return Err(self.new_err(EvalErrType::UnexpectedEOF));
                    }
                };
                Ok(Some(OpFrame::PubKey(key)))
            }
            o if o == Operand::OpIf as u8 => Ok(Some(OpFrame::OpIf)),
            o if o == Operand::OpElse as u8 => Ok(Some(OpFrame::OpElse)),
            o if o == Operand::OpEndIf as u8 => Ok(Some(OpFrame::OpEndIf)),
            o if o == Operand::OpReturn as u8 => Ok(Some(OpFrame::OpReturn)),
            o if o == Operand::OpCheckSig as u8 => Ok(Some(OpFrame::OpCheckSig)),
            _ => Err(self.new_err(EvalErrType::UnknownOp)),
        }
    }

    fn new_err(&self, err: EvalErrType) -> EvalErr {
        EvalErr::new(self.pos, err)
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;

    use super::*;
    use crate::asset::Asset;
    use crate::crypto::KeyPair;
    use crate::tx::{SignTx, TransferTx, Tx, TxType};

    #[test]
    fn true_only_script() {
        let mut engine = new_engine(Builder::new().push(OpFrame::True));
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn false_only_script() {
        let mut engine = new_engine(Builder::new().push(OpFrame::False));
        assert!(!engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn if_script() {
        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::False)
                .push(OpFrame::OpEndIf),
        );
        assert!(!engine.eval().unwrap());
        assert!(engine.stack.is_empty());

        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::True)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn if_script_with_ret() {
        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::False)
                    .push(OpFrame::OpReturn)
                .push(OpFrame::OpEndIf)
                .push(OpFrame::True),
        );
        assert!(!engine.eval().unwrap());
        assert!(engine.stack.is_empty());

        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::False)
                .push(OpFrame::OpIf)
                    .push(OpFrame::False)
                .push(OpFrame::OpElse)
                    .push(OpFrame::True)
                    .push(OpFrame::OpReturn)
                .push(OpFrame::OpEndIf)
                .push(OpFrame::False),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn branch_if() {
        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::True)
                .push(OpFrame::OpElse)
                    .push(OpFrame::False)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());

        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::False)
                .push(OpFrame::OpIf)
                    .push(OpFrame::False)
                .push(OpFrame::OpElse)
                    .push(OpFrame::True)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn nested_branch_if() {
        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::True)
                    .push(OpFrame::OpIf)
                        .push(OpFrame::True)
                    .push(OpFrame::OpEndIf)
                .push(OpFrame::OpElse)
                    .push(OpFrame::False)
                    .push(OpFrame::OpIf)
                        .push(OpFrame::False)
                    .push(OpFrame::OpEndIf)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());

        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::False)
                .push(OpFrame::OpIf)
                    .push(OpFrame::True)
                    .push(OpFrame::OpIf)
                        .push(OpFrame::False)
                    .push(OpFrame::OpEndIf)
                .push(OpFrame::OpElse)
                    .push(OpFrame::True)
                    .push(OpFrame::OpIf)
                        .push(OpFrame::True)
                    .push(OpFrame::OpEndIf)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn fail_invalid_stack_on_return() {
        let key = KeyPair::gen_keypair().0;
        let mut engine = new_engine(Builder::new().push(OpFrame::PubKey(key)));
        assert_eq!(
            engine.eval().unwrap_err().err,
            EvalErrType::InvalidItemOnStack
        );
    }

    #[test]
    fn fail_invalid_if_cmp() {
        let key = KeyPair::gen_keypair().0;
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::PubKey(key))
                .push(OpFrame::OpIf),
        );
        assert_eq!(
            engine.eval().unwrap_err().err,
            EvalErrType::InvalidItemOnStack
        );
    }

    #[test]
    fn fail_unended_if() {
        let mut engine = new_engine(Builder::new().push(OpFrame::True).push(OpFrame::OpIf));
        assert_eq!(engine.eval().unwrap_err().err, EvalErrType::UnexpectedEOF);

        let mut engine = new_engine(Builder::new().push(OpFrame::False).push(OpFrame::OpIf));
        assert_eq!(engine.eval().unwrap_err().err, EvalErrType::UnexpectedEOF);
    }

    #[test]
    fn checksig() {
        let key = KeyPair::gen_keypair();
        let mut engine = new_engine_with_signers(
            &[key],
            Builder::new()
                .push(OpFrame::PubKey(key.0.clone()))
                .push(OpFrame::OpCheckSig),
        );
        assert!(engine.eval().unwrap());

        let other = KeyPair::gen_keypair();
        let mut engine = new_engine_with_signers(
            &[key],
            Builder::new()
                .push(OpFrame::PubKey(other.0.clone()))
                .push(OpFrame::OpCheckSig),
        );
        assert!(!engine.eval().unwrap());

        let mut engine = new_engine_with_signers(
            &[other],
            Builder::new()
                .push(OpFrame::PubKey(key.0))
                .push(OpFrame::OpCheckSig),
        );
        assert!(!engine.eval().unwrap());
    }

    fn new_engine<'a>(builder: Builder) -> ScriptEngine<'a> {
        let from = KeyPair::gen_keypair();
        new_engine_with_signers(&[from], builder)
    }

    fn new_engine_with_signers<'a>(keys: &[KeyPair], b: Builder) -> ScriptEngine<'a> {
        let to = KeyPair::gen_keypair();
        let script = b.build();

        let mut tx = TransferTx {
            base: Tx {
                tx_type: TxType::TRANSFER,
                timestamp: 1500000000,
                fee: Asset::from_str("1 GOLD").unwrap(),
                signature_pairs: vec![],
            },
            from: keys[0].clone().0.into(),
            to: to.clone().0.into(),
            amount: Asset::from_str("10 GOLD").unwrap(),
            script: script.clone(),
            memo: vec![],
        };
        for key in keys {
            tx.append_sign(&key);
        }

        ScriptEngine::checked_new(TxVariant::TransferTx(tx), script).unwrap()
    }
}
<commit_msg>Fix tests<commit_after>use sodiumoxide::crypto::sign;
use std::borrow::Cow;

use super::stack::*;
use super::*;
use crate::crypto::PublicKey;
use crate::tx::TxVariant;

macro_rules! map_err_type {
    ($self:expr, $var:expr) => {
        $var.map_err(|e| $self.new_err(e))
    };
}

pub struct ScriptEngine<'a> {
    script: Cow<'a, Script>,
    tx: Cow<'a, TxVariant>,
    pos: usize,
    stack: Stack,
}

impl<'a> ScriptEngine<'a> {
    pub fn checked_new<T, S>(tx: T, script: S) -> Option<Self>
    where
        T: Into<Cow<'a, TxVariant>>,
        S: Into<Cow<'a, Script>>,
    {
        let script = script.into();
        let tx = tx.into();
        if script.len() > MAX_BYTE_SIZE {
            return None;
        }
        Some(Self {
            script,
            tx,
            pos: 0,
            stack: Stack::new(),
        })
    }

    pub fn eval(&mut self) -> Result<bool, EvalErr> {
        self.pos = 0;
        let mut if_marker = 0;
        let mut ignore_else = false;
        while let Some(op) = self.consume_op()? {
            match op {
                // Control
                OpFrame::OpIf => {
                    if_marker += 1;
                    ignore_else = map_err_type!(self, self.stack.pop_bool())?;
                    if ignore_else {
                        continue;
                    }
                    let req_if_marker = if_marker;
                    self.consume_op_until(|op| {
                        if op == OpFrame::OpIf {
                            if_marker += 1;
                            false
                        } else if op == OpFrame::OpElse {
                            if_marker == req_if_marker
                        } else if op == OpFrame::OpEndIf {
                            let do_break = if_marker == req_if_marker;
                            if_marker -= 1;
                            do_break
                        } else {
                            false
                        }
                    })?;
                }
                OpFrame::OpElse => {
                    if !ignore_else {
                        continue;
                    }
                    let req_if_marker = if_marker;
                    self.consume_op_until(|op| {
                        if op == OpFrame::OpIf {
                            if_marker += 1;
                            false
                        } else if op == OpFrame::OpElse {
                            if_marker == req_if_marker
                        } else if op == OpFrame::OpEndIf {
                            let do_break = if_marker == req_if_marker;
                            if_marker -= 1;
                            do_break
                        } else {
                            false
                        }
                    })?;
                }
                OpFrame::OpEndIf => {
                    if_marker -= 1;
                }
                OpFrame::OpReturn => {
                    if_marker = 0;
                    break;
                }
                // Crypto
                OpFrame::OpCheckSig => {
                    let key = map_err_type!(self, self.stack.pop_pubkey())?;
                    if self.tx.signature_pairs.len() != 1 {
                        map_err_type!(self, self.stack.push(false))?;
                        continue;
                    }
                    let mut buf = Vec::with_capacity(4096);
                    self.tx.encode(&mut buf);
                    let success = key.verify(&buf, &self.tx.signature_pairs[0].signature);
                    map_err_type!(self, self.stack.push(success))?;
                }
                // Handle push ops
                _ => {
                    map_err_type!(self, self.stack.push(op))?;
                }
            }
        }

        if if_marker > 0 {
            return Err(self.new_err(EvalErrType::UnexpectedEOF));
        }

        // Scripts must return true or false
        map_err_type!(self, self.stack.pop_bool())
    }

    fn consume_op_until<F>(&mut self, mut filter: F) -> Result<(), EvalErr>
    where
        F: FnMut(OpFrame) -> bool,
    {
        loop {
            match self.consume_op()? {
                Some(op) => {
                    if filter(op) {
                        break;
                    }
                }
                None => return Err(self.new_err(EvalErrType::UnexpectedEOF)),
            }
        }

        Ok(())
    }

    fn consume_op(&mut self) -> Result<Option<OpFrame>, EvalErr> {
        if self.pos == self.script.len() {
            return Ok(None);
        }
        let byte = self.script[self.pos];
        self.pos += 1;

        match byte {
            o if o == Operand::PushFalse as u8 => Ok(Some(OpFrame::False)),
            o if o == Operand::PushTrue as u8 => Ok(Some(OpFrame::True)),
            o if o == Operand::PushPubKey as u8 => {
                let slice = self.pos..self.pos + sign::PUBLICKEYBYTES;
                let key = match self.script.get(slice) {
                    Some(slice) => {
                        self.pos += sign::PUBLICKEYBYTES;
                        PublicKey::from_slice(slice).unwrap()
                    }
                    None => {
                        return Err(self.new_err(EvalErrType::UnexpectedEOF));
                    }
                };
                Ok(Some(OpFrame::PubKey(key)))
            }
            o if o == Operand::OpIf as u8 => Ok(Some(OpFrame::OpIf)),
            o if o == Operand::OpElse as u8 => Ok(Some(OpFrame::OpElse)),
            o if o == Operand::OpEndIf as u8 => Ok(Some(OpFrame::OpEndIf)),
            o if o == Operand::OpReturn as u8 => Ok(Some(OpFrame::OpReturn)),
            o if o == Operand::OpCheckSig as u8 => Ok(Some(OpFrame::OpCheckSig)),
            _ => Err(self.new_err(EvalErrType::UnknownOp)),
        }
    }

    fn new_err(&self, err: EvalErrType) -> EvalErr {
        EvalErr::new(self.pos, err)
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;

    use super::*;
    use crate::asset::Asset;
    use crate::crypto::KeyPair;
    use crate::tx::{SignTx, TransferTx, Tx, TxType};

    #[test]
    fn true_only_script() {
        let mut engine = new_engine(Builder::new().push(OpFrame::True));
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn false_only_script() {
        let mut engine = new_engine(Builder::new().push(OpFrame::False));
        assert!(!engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn if_script() {
        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::False)
                .push(OpFrame::OpEndIf),
        );
        assert!(!engine.eval().unwrap());
        assert!(engine.stack.is_empty());

        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::True)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn if_script_with_ret() {
        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::False)
                    .push(OpFrame::OpReturn)
                .push(OpFrame::OpEndIf)
                .push(OpFrame::True),
        );
        assert!(!engine.eval().unwrap());
        assert!(engine.stack.is_empty());

        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::False)
                .push(OpFrame::OpIf)
                    .push(OpFrame::False)
                .push(OpFrame::OpElse)
                    .push(OpFrame::True)
                    .push(OpFrame::OpReturn)
                .push(OpFrame::OpEndIf)
                .push(OpFrame::False),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn branch_if() {
        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::True)
                .push(OpFrame::OpElse)
                    .push(OpFrame::False)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());

        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::False)
                .push(OpFrame::OpIf)
                    .push(OpFrame::False)
                .push(OpFrame::OpElse)
                    .push(OpFrame::True)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn nested_branch_if() {
        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::True)
                .push(OpFrame::OpIf)
                    .push(OpFrame::True)
                    .push(OpFrame::OpIf)
                        .push(OpFrame::True)
                    .push(OpFrame::OpEndIf)
                .push(OpFrame::OpElse)
                    .push(OpFrame::False)
                    .push(OpFrame::OpIf)
                        .push(OpFrame::False)
                    .push(OpFrame::OpEndIf)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());

        #[rustfmt::skip]
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::False)
                .push(OpFrame::OpIf)
                    .push(OpFrame::True)
                    .push(OpFrame::OpIf)
                        .push(OpFrame::False)
                    .push(OpFrame::OpEndIf)
                .push(OpFrame::OpElse)
                    .push(OpFrame::True)
                    .push(OpFrame::OpIf)
                        .push(OpFrame::True)
                    .push(OpFrame::OpEndIf)
                .push(OpFrame::OpEndIf),
        );
        assert!(engine.eval().unwrap());
        assert!(engine.stack.is_empty());
    }

    #[test]
    fn fail_invalid_stack_on_return() {
        let key = KeyPair::gen_keypair().0;
        let mut engine = new_engine(Builder::new().push(OpFrame::PubKey(key)));
        assert_eq!(
            engine.eval().unwrap_err().err,
            EvalErrType::InvalidItemOnStack
        );
    }

    #[test]
    fn fail_invalid_if_cmp() {
        let key = KeyPair::gen_keypair().0;
        let mut engine = new_engine(
            Builder::new()
                .push(OpFrame::PubKey(key))
                .push(OpFrame::OpIf),
        );
        assert_eq!(
            engine.eval().unwrap_err().err,
            EvalErrType::InvalidItemOnStack
        );
    }

    #[test]
    fn fail_unended_if() {
        let mut engine = new_engine(Builder::new().push(OpFrame::True).push(OpFrame::OpIf));
        assert_eq!(engine.eval().unwrap_err().err, EvalErrType::UnexpectedEOF);

        let mut engine = new_engine(Builder::new().push(OpFrame::False).push(OpFrame::OpIf));
        assert_eq!(engine.eval().unwrap_err().err, EvalErrType::UnexpectedEOF);
    }

    #[test]
    fn checksig() {
        let key = KeyPair::gen_keypair();
        let mut engine = new_engine_with_signers(
            &[key.clone()],
            Builder::new()
                .push(OpFrame::PubKey(key.0.clone()))
                .push(OpFrame::OpCheckSig),
        );
        assert!(engine.eval().unwrap());

        let other = KeyPair::gen_keypair();
        let mut engine = new_engine_with_signers(
            &[key.clone()],
            Builder::new()
                .push(OpFrame::PubKey(other.0.clone()))
                .push(OpFrame::OpCheckSig),
        );
        assert!(!engine.eval().unwrap());

        let mut engine = new_engine_with_signers(
            &[other],
            Builder::new()
                .push(OpFrame::PubKey(key.0))
                .push(OpFrame::OpCheckSig),
        );
        assert!(!engine.eval().unwrap());
    }

    fn new_engine<'a>(builder: Builder) -> ScriptEngine<'a> {
        let from = KeyPair::gen_keypair();
        new_engine_with_signers(&[from], builder)
    }

    fn new_engine_with_signers<'a>(keys: &[KeyPair], b: Builder) -> ScriptEngine<'a> {
        let to = KeyPair::gen_keypair();
        let script = b.build();

        let mut tx = TransferTx {
            base: Tx {
                tx_type: TxType::TRANSFER,
                timestamp: 1500000000,
                fee: Asset::from_str("1 GOLD").unwrap(),
                signature_pairs: vec![],
            },
            from: keys[0].clone().0.into(),
            to: to.clone().0.into(),
            amount: Asset::from_str("10 GOLD").unwrap(),
            script: script.clone(),
            memo: vec![],
        };
        for key in keys {
            tx.append_sign(&key);
        }

        ScriptEngine::checked_new(TxVariant::TransferTx(tx), script).unwrap()
    }
}
<|endoftext|>


<commit_before>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;
use util::Id;

use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

use std::hash::{Hash, Hasher};
use std::collections::{HashSet, HashMap};

/// A marker for Id.
/// Only useful for writing `Id<ServiceId>`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ServiceId;

/// Metadata on a service. A service is a device or collection of devices
/// that may offer services. The FoxBox itself is a service offering
/// services such as a clock, communicating with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find services and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all services
    /// placed in the entrance of his house, or a tag "blue" to a service
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    pub tags: HashSet<String>,

    /// An id unique to this service.
    pub id: Id<ServiceId>,

    /// Channels connected directly to this service.
    pub getters: HashMap<Id<Getter>, Channel<Getter>>,
    pub setters: HashMap<Id<Setter>, Channel<Setter>>,
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ChannelKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ChannelKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ChannelKind::*;
        use values::Type;
        match *self {
            Ready => Type::Unit,
            OnOff => Type::OnOff,
            OpenClosed => Type::OpenClosed,
            CurrentTime => Type::TimeStamp,
            CurrentTimeOfDay | RemainingTime => Type::Duration,
            Thermostat | ActualTemperature => Type::Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }
}

/// A getter operation available on a channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Getter {
    /// The kind of value that can be obtained from this channel.
    pub kind: ChannelKind,

    /// If `Some(duration)`, this channel can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the channel cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    #[serde(default)]
    pub poll: Option<ValDuration>,

    /// If `Some(duration)`, this channel can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the channel cannot send data to the FoxBox
    /// and needs to be polled.
    #[serde(default)]
    pub trigger: Option<ValDuration>,

    /// If `true`, this channel supports watching for specific
    /// changes.
    #[serde(default)]
    pub watch: bool,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    pub updated: Option<TimeStamp>,
}
impl IOMechanism for Getter {
}

/// An setter operation available on an channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Setter {
    /// The kind of value that can be sent to this channel.
    pub kind: ChannelKind,

    /// If `Some(duration)`, this channel supports pushing,
    /// i.e. the FoxBox can send values.
    #[serde(default)]
    pub push: Option<ValDuration>,

    /// Date at which the latest value was sent to the channel.
    #[serde(default)]
    pub updated: Option<TimeStamp>,
}
impl IOMechanism for Setter {
}

/// An channel represents a single place where data can enter or
/// leave a device. Note that channels support either a single kind
/// of getter or a single kind of setter. Devices that support both
/// getters or setters, or several kinds of getters, or several kinds of
/// setters, are represented as services containing several channels.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Channel<IO> where IO: IOMechanism {
    /// Tags describing the channel.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup channels for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    pub tags: HashSet<String>,

    /// An id unique to this channel.
    pub id: Id<IO>,

    /// The service owning this channel.
    pub service: Id<ServiceId>,

    /// The update mechanism for this channel.
    pub mechanism: IO,

    /// The last time the device was seen.
    #[serde(default)]
    pub last_seen: Option<TimeStamp>,
}
impl<IO> Eq for Channel<IO> where IO: IOMechanism {
}
impl<IO> PartialEq for Channel<IO> where IO: IOMechanism {
     fn eq(&self, other: &Self) -> bool {
         self.id.eq(&other.id)
     }
}
impl<IO> Hash for Channel<IO> where IO: IOMechanism {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.id.hash(state)
    }
}

/// The communication mechanism used by the channel.
pub trait IOMechanism: Deserialize + Serialize {
}

<commit_msg>[fxbox/taxonomy] Service::empty<commit_after>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;
use util::Id;

use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

use std::hash::{Hash, Hasher};
use std::collections::{HashSet, HashMap};

/// A marker for Id.
/// Only useful for writing `Id<ServiceId>`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ServiceId;

/// Metadata on a service. A service is a device or collection of devices
/// that may offer services. The FoxBox itself is a service offering
/// services such as a clock, communicating with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find services and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all services
    /// placed in the entrance of his house, or a tag "blue" to a service
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    pub tags: HashSet<String>,

    /// An id unique to this service.
    pub id: Id<ServiceId>,

    /// Channels connected directly to this service.
    pub getters: HashMap<Id<Getter>, Channel<Getter>>,
    pub setters: HashMap<Id<Setter>, Channel<Setter>>,
}
impl Service {
    /// Create an empty service.
    pub fn empty(id: Id<ServiceId>) -> Self {
        Service {
            tags: HashSet::new(),
            getters: HashMap::new(),
            setters: HashMap::new(),
            id: id,
        }
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ChannelKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ChannelKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ChannelKind::*;
        use values::Type;
        match *self {
            Ready => Type::Unit,
            OnOff => Type::OnOff,
            OpenClosed => Type::OpenClosed,
            CurrentTime => Type::TimeStamp,
            CurrentTimeOfDay | RemainingTime => Type::Duration,
            Thermostat | ActualTemperature => Type::Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }
}

/// A getter operation available on a channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Getter {
    /// The kind of value that can be obtained from this channel.
    pub kind: ChannelKind,

    /// If `Some(duration)`, this channel can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the channel cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    #[serde(default)]
    pub poll: Option<ValDuration>,

    /// If `Some(duration)`, this channel can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the channel cannot send data to the FoxBox
    /// and needs to be polled.
    #[serde(default)]
    pub trigger: Option<ValDuration>,

    /// If `true`, this channel supports watching for specific
    /// changes.
    #[serde(default)]
    pub watch: bool,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    pub updated: Option<TimeStamp>,
}
impl IOMechanism for Getter {
}

/// An setter operation available on an channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Setter {
    /// The kind of value that can be sent to this channel.
    pub kind: ChannelKind,

    /// If `Some(duration)`, this channel supports pushing,
    /// i.e. the FoxBox can send values.
    #[serde(default)]
    pub push: Option<ValDuration>,

    /// Date at which the latest value was sent to the channel.
    #[serde(default)]
    pub updated: Option<TimeStamp>,
}
impl IOMechanism for Setter {
}

/// An channel represents a single place where data can enter or
/// leave a device. Note that channels support either a single kind
/// of getter or a single kind of setter. Devices that support both
/// getters or setters, or several kinds of getters, or several kinds of
/// setters, are represented as services containing several channels.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Channel<IO> where IO: IOMechanism {
    /// Tags describing the channel.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup channels for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    pub tags: HashSet<String>,

    /// An id unique to this channel.
    pub id: Id<IO>,

    /// The service owning this channel.
    pub service: Id<ServiceId>,

    /// The update mechanism for this channel.
    pub mechanism: IO,

    /// The last time the device was seen.
    #[serde(default)]
    pub last_seen: Option<TimeStamp>,
}
impl<IO> Eq for Channel<IO> where IO: IOMechanism {
}
impl<IO> PartialEq for Channel<IO> where IO: IOMechanism {
     fn eq(&self, other: &Self) -> bool {
         self.id.eq(&other.id)
     }
}
impl<IO> Hash for Channel<IO> where IO: IOMechanism {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.id.hash(state)
    }
}

/// The communication mechanism used by the channel.
pub trait IOMechanism: Deserialize + Serialize {
}

<|endoftext|>


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

use rustc_serialize::json::{decode};
use time;
use url::Url;
use net_traits::IncludeSubdomains;
use resource_task::{IPV4_REGEX, IPV6_REGEX};

use std::str::{from_utf8};

use util::resource_files::read_resource_file;

#[derive(RustcDecodable, RustcEncodable, Clone)]
pub struct HSTSEntry {
    pub host: String,
    pub include_subdomains: bool,
    pub max_age: Option<u64>,
    pub timestamp: Option<u64>
}

impl HSTSEntry {
    pub fn new(host: String, subdomains: IncludeSubdomains, max_age: Option<u64>) -> Option<HSTSEntry> {
        if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) {
            None
        } else {
            Some(HSTSEntry {
                host: host,
                include_subdomains: (subdomains == IncludeSubdomains::Included),
                max_age: max_age,
                timestamp: Some(time::get_time().sec as u64)
            })
        }
    }

    pub fn is_expired(&self) -> bool {
        match (self.max_age, self.timestamp) {
            (Some(max_age), Some(timestamp)) => {
                (time::get_time().sec as u64) - timestamp >= max_age
            },

            _ => false
        }
    }

    fn matches_domain(&self, host: &str) -> bool {
        !self.is_expired() && self.host == host
    }

    fn matches_subdomain(&self, host: &str) -> bool {
        !self.is_expired() && host.ends_with(&format!(".{}", self.host))
    }
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
pub struct HSTSList {
    pub entries: Vec<HSTSEntry>
}

impl HSTSList {
    pub fn new() -> HSTSList {
        HSTSList {
            entries: vec![]
        }
    }

    pub fn new_from_preload(preload_content: &str) -> Option<HSTSList> {
        decode(preload_content).ok()
    }

    pub fn is_host_secure(&self, host: &str) -> bool {
        // TODO - Should this be faster than O(n)? The HSTS list is only a few
        // hundred or maybe thousand entries...
        //
        // Could optimise by searching for exact matches first (via a map or
        // something), then checking for subdomains.
        self.entries.iter().any(|e| {
            if e.include_subdomains {
                e.matches_subdomain(host) || e.matches_domain(host)
            } else {
                e.matches_domain(host)
            }
        })
    }

    fn has_domain(&self, host: &str) -> bool {
        self.entries.iter().any(|e| {
            e.matches_domain(&host)
        })
    }

    fn has_subdomain(&self, host: &str) -> bool {
        self.entries.iter().any(|e| {
            e.matches_subdomain(host)
        })
    }

    pub fn push(&mut self, entry: HSTSEntry) {
        let have_domain = self.has_domain(&entry.host);
        let have_subdomain = self.has_subdomain(&entry.host);

        if !have_domain && !have_subdomain {
            self.entries.push(entry);
        } else if !have_subdomain {
            for e in &mut self.entries {
                if e.matches_domain(&entry.host) {
                    e.include_subdomains = entry.include_subdomains;
                    e.max_age = entry.max_age;
                }
            }
        }
    }
}

pub fn preload_hsts_domains() -> Option<HSTSList> {
    read_resource_file(&["hsts_preload.json"]).ok().and_then(|bytes| {
        from_utf8(&bytes).ok().and_then(|hsts_preload_content| {
            HSTSList::new_from_preload(hsts_preload_content)
        })
    })
}

pub fn secure_url(url: &Url) -> Url {
    if &*url.scheme == "http" {
        let mut secure_url = url.clone();
        secure_url.scheme = "https".to_string();
        Url::parse(&secure_url.serialize()).unwrap()
    } else {
        url.clone()
    }
}

<commit_msg>Uses the approach suggested by @SimonSapin for changing Url scheme<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use rustc_serialize::json::{decode};
use time;
use url::Url;
use net_traits::IncludeSubdomains;
use resource_task::{IPV4_REGEX, IPV6_REGEX};

use std::str::{from_utf8};

use util::resource_files::read_resource_file;

#[derive(RustcDecodable, RustcEncodable, Clone)]
pub struct HSTSEntry {
    pub host: String,
    pub include_subdomains: bool,
    pub max_age: Option<u64>,
    pub timestamp: Option<u64>
}

impl HSTSEntry {
    pub fn new(host: String, subdomains: IncludeSubdomains, max_age: Option<u64>) -> Option<HSTSEntry> {
        if IPV4_REGEX.is_match(&host) || IPV6_REGEX.is_match(&host) {
            None
        } else {
            Some(HSTSEntry {
                host: host,
                include_subdomains: (subdomains == IncludeSubdomains::Included),
                max_age: max_age,
                timestamp: Some(time::get_time().sec as u64)
            })
        }
    }

    pub fn is_expired(&self) -> bool {
        match (self.max_age, self.timestamp) {
            (Some(max_age), Some(timestamp)) => {
                (time::get_time().sec as u64) - timestamp >= max_age
            },

            _ => false
        }
    }

    fn matches_domain(&self, host: &str) -> bool {
        !self.is_expired() && self.host == host
    }

    fn matches_subdomain(&self, host: &str) -> bool {
        !self.is_expired() && host.ends_with(&format!(".{}", self.host))
    }
}

#[derive(RustcDecodable, RustcEncodable, Clone)]
pub struct HSTSList {
    pub entries: Vec<HSTSEntry>
}

impl HSTSList {
    pub fn new() -> HSTSList {
        HSTSList {
            entries: vec![]
        }
    }

    pub fn new_from_preload(preload_content: &str) -> Option<HSTSList> {
        decode(preload_content).ok()
    }

    pub fn is_host_secure(&self, host: &str) -> bool {
        // TODO - Should this be faster than O(n)? The HSTS list is only a few
        // hundred or maybe thousand entries...
        //
        // Could optimise by searching for exact matches first (via a map or
        // something), then checking for subdomains.
        self.entries.iter().any(|e| {
            if e.include_subdomains {
                e.matches_subdomain(host) || e.matches_domain(host)
            } else {
                e.matches_domain(host)
            }
        })
    }

    fn has_domain(&self, host: &str) -> bool {
        self.entries.iter().any(|e| {
            e.matches_domain(&host)
        })
    }

    fn has_subdomain(&self, host: &str) -> bool {
        self.entries.iter().any(|e| {
            e.matches_subdomain(host)
        })
    }

    pub fn push(&mut self, entry: HSTSEntry) {
        let have_domain = self.has_domain(&entry.host);
        let have_subdomain = self.has_subdomain(&entry.host);

        if !have_domain && !have_subdomain {
            self.entries.push(entry);
        } else if !have_subdomain {
            for e in &mut self.entries {
                if e.matches_domain(&entry.host) {
                    e.include_subdomains = entry.include_subdomains;
                    e.max_age = entry.max_age;
                }
            }
        }
    }
}

pub fn preload_hsts_domains() -> Option<HSTSList> {
    read_resource_file(&["hsts_preload.json"]).ok().and_then(|bytes| {
        from_utf8(&bytes).ok().and_then(|hsts_preload_content| {
            HSTSList::new_from_preload(hsts_preload_content)
        })
    })
}

pub fn secure_url(url: &Url) -> Url {
    if &*url.scheme == "http" {
        let mut secure_url = url.clone();
        secure_url.scheme = "https".to_string();
        secure_url.relative_scheme_data_mut()
            .map(|scheme_data| {
                scheme_data.default_port = Some(443);
            });
        secure_url
    } else {
        url.clone()
    }
}

<|endoftext|>


<commit_before>use core_graphics::display;
use std::collections::VecDeque;

pub struct MonitorID(u32);

pub fn get_available_monitors() -> VecDeque<MonitorID> {
    let mut monitors = VecDeque::new();
    unsafe {
        let max_displays = 10u32;
        let mut active_displays = [0u32; 10];
        let mut display_count = 0;
        display::CGGetActiveDisplayList(max_displays,
                                                        &mut active_displays[0],
                                                        &mut display_count);
        for i in range(0, display_count as usize) {
            monitors.push_back(MonitorID(active_displays[i]));
        }
    }
    monitors
}

pub fn get_primary_monitor() -> MonitorID {
    let id = unsafe {
        MonitorID(display::CGMainDisplayID())
    };
    id
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        let MonitorID(display_id) = *self;
        let screen_num = unsafe {
            display::CGDisplayModelNumber(display_id)
        };
        Some(format!("Monitor #{}", screen_num))
    }

    pub fn get_dimensions(&self) -> (u32, u32) {
        let MonitorID(display_id) = *self;
        let dimension = unsafe {
            let height = display::CGDisplayPixelsHigh(display_id);
            let width = display::CGDisplayPixelsWide(display_id);
            (width as u32, height as u32)
        };
        dimension
    }
}
<commit_msg>Upgrade to latest Rust<commit_after>use core_graphics::display;
use std::collections::VecDeque;

pub struct MonitorID(u32);

pub fn get_available_monitors() -> VecDeque<MonitorID> {
    let mut monitors = VecDeque::new();
    unsafe {
        let max_displays = 10u32;
        let mut active_displays = [0u32; 10];
        let mut display_count = 0;
        display::CGGetActiveDisplayList(max_displays,
                                                        &mut active_displays[0],
                                                        &mut display_count);
        for i in 0..display_count as usize {
            monitors.push_back(MonitorID(active_displays[i]));
        }
    }
    monitors
}

pub fn get_primary_monitor() -> MonitorID {
    let id = unsafe {
        MonitorID(display::CGMainDisplayID())
    };
    id
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        let MonitorID(display_id) = *self;
        let screen_num = unsafe {
            display::CGDisplayModelNumber(display_id)
        };
        Some(format!("Monitor #{}", screen_num))
    }

    pub fn get_dimensions(&self) -> (u32, u32) {
        let MonitorID(display_id) = *self;
        let dimension = unsafe {
            let height = display::CGDisplayPixelsHigh(display_id);
            let width = display::CGDisplayPixelsWide(display_id);
            (width as u32, height as u32)
        };
        dimension
    }
}
<|endoftext|>


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

//! Color channel conversions and utility methods

pub trait Channel: Primitive + Orderable {
    priv fn from<T:Channel>(chan: T) -> Self;
    pub fn to_channel<T:Channel>(&self) -> T;
    pub fn to_channel_u8(&self)  -> u8;
    pub fn to_channel_u16(&self) -> u16;
    pub fn to_channel_f32(&self) -> f32;
    pub fn to_channel_f64(&self) -> f64;

    pub fn invert_channel(&self) -> Self;
}

impl Channel for u8 {
    #[inline] priv fn from<T:Channel>(chan: T) -> u8 { chan.to_channel_u8() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self as u16 << 8) | (*self) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self as f32) / (0xFF as f32) }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self as f64) / (0xFF as f64) }

    #[inline] pub fn invert_channel(&self) -> u8 { !(*self) }
}

impl Channel for u16 {
    #[inline] priv fn from<T:Channel>(chan: T) -> u16 { chan.to_channel_u16() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self >> 8) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF as f32 }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF as f64 }

    #[inline] pub fn invert_channel(&self) -> u16 { !(*self) }
}

impl Channel for f32 {
    #[inline] priv fn from<T:Channel>(chan: T) -> f32 { chan.to_channel_f32() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) * (0xFF as f32) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF as f32) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 }

    #[inline] pub fn invert_channel(&self) -> f32 { 1.0 - (*self) }
}

impl Channel for f64 {
    #[inline] priv fn from<T:Channel>(chan: T) -> f64 { chan.to_channel_f64() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) * (0xFF as f64) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF as f64) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) as f32 }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) }

    #[inline] pub fn invert_channel(&self) -> f64 { 1.0 - (*self) }
}

pub trait FloatChannel: Float + Channel {
    pub fn normalize_channel(&self) -> Self;
    pub fn normalize_degrees(&self) -> Self;
    pub fn invert_degrees(&self) -> Self;
}

impl FloatChannel for f32 {
    #[inline] pub fn normalize_channel(&self) -> f32 { self.clamp(&0.0, &1.0) }
    #[inline] pub fn normalize_degrees(&self) -> f32 { (*self) % 360.0 }
    #[inline] pub fn invert_degrees(&self) -> f32 { ((*self) + 180.0).normalize_degrees() }
}

impl FloatChannel for f64 {
    #[inline] pub fn normalize_channel(&self) -> f64 { self.clamp(&0.0, &1.0) }
    #[inline] pub fn normalize_degrees(&self) -> f64 { (*self) % 360.0 }
    #[inline] pub fn invert_degrees(&self) -> f64 { ((*self) + 180.0).normalize_degrees() }
}

#[cfg(test)]
mod tests {
    use color::Channel;

    #[test]
    fn test_to_channel_u8() {
        assert_eq!(0x00_u8.to_channel_u8(), 0x00_u8);
        assert_eq!(0x30_u8.to_channel_u8(), 0x30_u8);
        assert_eq!(0x66_u8.to_channel_u8(), 0x66_u8);
        assert_eq!(0xA0_u8.to_channel_u8(), 0xA0_u8);
        assert_eq!(0xFF_u8.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x00_u8.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x30_u8.to_channel_u16(), 0x3030_u16);
        assert_eq!(0x66_u8.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xA0_u8.to_channel_u16(), 0xA0A0_u16);
        assert_eq!(0xFF_u8.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x00_u8.to_channel_f32(), 0f32);
        assert_eq!(0xFF_u8.to_channel_f32(), 1f32);

        assert_eq!(0x00_u8.to_channel_f64(), 0f64);
        assert_eq!(0xFF_u8.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u8() {
        assert_eq!(0x00_u8.invert_channel(), 0xFF_u8);
        assert_eq!(0x66_u8.invert_channel(), 0x99_u8);
        assert_eq!(0xFF_u8.invert_channel(), 0x00_u8);
    }

    #[test]
    fn test_to_channel_u16() {
        assert_eq!(0x0000_u16.to_channel_u8(), 0x00_u8);
        assert_eq!(0x3300_u16.to_channel_u8(), 0x33_u8);
        assert_eq!(0x6666_u16.to_channel_u8(), 0x66_u8);
        assert_eq!(0xAA00_u16.to_channel_u8(), 0xAA_u8);
        assert_eq!(0xFFFF_u16.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x0000_u16.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x3300_u16.to_channel_u16(), 0x3300_u16);
        assert_eq!(0x6666_u16.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xAA00_u16.to_channel_u16(), 0xAA00_u16);
        assert_eq!(0xFFFF_u16.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x0000_u16.to_channel_f32(), 0f32);
        assert_eq!(0xFFFF_u16.to_channel_f32(), 1f32);

        assert_eq!(0x0000_u16.to_channel_f64(), 0f64);
        assert_eq!(0xFFFF_u16.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u16() {
        assert_eq!(0x0000_u16.invert_channel(), 0xFFFF_u16);
        assert_eq!(0x6666_u16.invert_channel(), 0x9999_u16);
        assert_eq!(0xFFFF_u16.invert_channel(), 0x0000_u16);
    }

    #[test]
    fn test_to_channel_f32() {
        assert_eq!(0.00f32.to_channel_u8(), 0x00);
        assert_eq!(0.25f32.to_channel_u8(), 0x3F);
        assert_eq!(0.50f32.to_channel_u8(), 0x7F);
        assert_eq!(0.75f32.to_channel_u8(), 0xBF);
        assert_eq!(1.00f32.to_channel_u8(), 0xFF);

        assert_eq!(0.00f32.to_channel_u16(), 0x0000);
        assert_eq!(0.25f32.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f32.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f32.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f32.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f32.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f32.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f32.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f32.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f32() {
        assert_eq!(0.00f32.invert_channel(), 1.00f32);
        assert_eq!(0.50f32.invert_channel(), 0.50f32);
        assert_eq!(1.00f32.invert_channel(), 0.00f32);
    }

    #[test]
    fn test_invert_degrees_f32() {
        assert_eq!(  0.00f32.invert_degrees(), 180.00f32);
        assert_eq!( 45.00f32.invert_degrees(), 225.00f32);
        assert_eq!( 90.00f32.invert_degrees(), 270.00f32);
        assert_eq!(360.00f32.invert_degrees(), 180.00f32);
        assert_eq!(720.00f32.invert_degrees(), 180.00f32);
    }

    #[test]
    fn test_to_channel_f64() {
        assert_eq!(0.00f64.to_channel_u8(), 0x00);
        assert_eq!(0.25f64.to_channel_u8(), 0x3F);
        assert_eq!(0.50f64.to_channel_u8(), 0x7F);
        assert_eq!(0.75f64.to_channel_u8(), 0xBF);
        assert_eq!(1.00f64.to_channel_u8(), 0xFF);

        assert_eq!(0.00f64.to_channel_u16(), 0x0000);
        assert_eq!(0.25f64.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f64.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f64.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f64.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f64.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f64.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f64.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f64.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f64() {
        assert_eq!(0.00f64.invert_channel(), 1.00f64);
        assert_eq!(0.50f64.invert_channel(), 0.50f64);
        assert_eq!(1.00f64.invert_channel(), 0.00f64);
    }

    #[test]
    fn test_invert_degrees_f64() {
        assert_eq!(  0.00f64.invert_degrees(), 180.00f64);
        assert_eq!( 45.00f64.invert_degrees(), 225.00f64);
        assert_eq!( 90.00f64.invert_degrees(), 270.00f64);
        assert_eq!(360.00f64.invert_degrees(), 180.00f64);
        assert_eq!(720.00f64.invert_degrees(), 180.00f64);
    }
}
<commit_msg>Fix normalize_degrees impls<commit_after>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Color channel conversions and utility methods

pub trait Channel: Primitive + Orderable {
    priv fn from<T:Channel>(chan: T) -> Self;
    pub fn to_channel<T:Channel>(&self) -> T;
    pub fn to_channel_u8(&self)  -> u8;
    pub fn to_channel_u16(&self) -> u16;
    pub fn to_channel_f32(&self) -> f32;
    pub fn to_channel_f64(&self) -> f64;

    pub fn invert_channel(&self) -> Self;
}

impl Channel for u8 {
    #[inline] priv fn from<T:Channel>(chan: T) -> u8 { chan.to_channel_u8() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self as u16 << 8) | (*self) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self as f32) / (0xFF as f32) }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self as f64) / (0xFF as f64) }

    #[inline] pub fn invert_channel(&self) -> u8 { !(*self) }
}

impl Channel for u16 {
    #[inline] priv fn from<T:Channel>(chan: T) -> u16 { chan.to_channel_u16() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self >> 8) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF as f32 }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF as f64 }

    #[inline] pub fn invert_channel(&self) -> u16 { !(*self) }
}

impl Channel for f32 {
    #[inline] priv fn from<T:Channel>(chan: T) -> f32 { chan.to_channel_f32() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) * (0xFF as f32) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF as f32) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 }

    #[inline] pub fn invert_channel(&self) -> f32 { 1.0 - (*self) }
}

impl Channel for f64 {
    #[inline] priv fn from<T:Channel>(chan: T) -> f64 { chan.to_channel_f64() }
    #[inlune] pub fn to_channel<T:Channel>(&self) -> T { Channel::from(*self) }
    #[inline] pub fn to_channel_u8(&self)  -> u8  { (*self) * (0xFF as f64) as u8 }
    #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF as f64) as u16 }
    #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) as f32 }
    #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) }

    #[inline] pub fn invert_channel(&self) -> f64 { 1.0 - (*self) }
}

pub trait FloatChannel: Float + Channel {
    pub fn normalize_channel(&self) -> Self;
    pub fn normalize_degrees(&self) -> Self;
    pub fn invert_degrees(&self) -> Self;
}

impl FloatChannel for f32 {
    #[inline] pub fn normalize_channel(&self) -> f32 {
        self.clamp(&0.0, &1.0)
    }

    #[inline] pub fn normalize_degrees(&self) -> f32 {
        if (*self) < 0.0 {
            (*self + 360.0) % 360.0
        } else {
            *self % 360.0
        }
    }

    #[inline] pub fn invert_degrees(&self) -> f32 {
        (*self + 180.0).normalize_degrees()
    }
}

impl FloatChannel for f64 {
    #[inline] pub fn normalize_channel(&self) -> f64 {
        self.clamp(&0.0, &1.0)
    }

    #[inline] pub fn normalize_degrees(&self) -> f64 {
        if (*self) < 0.0 {
            (*self + 360.0) % 360.0
        } else {
            *self % 360.0
        }
    }

    #[inline] pub fn invert_degrees(&self) -> f64 {
        (*self + 180.0).normalize_degrees()
    }
}

#[cfg(test)]
mod tests {
    use color::Channel;

    #[test]
    fn test_to_channel_u8() {
        assert_eq!(0x00_u8.to_channel_u8(), 0x00_u8);
        assert_eq!(0x30_u8.to_channel_u8(), 0x30_u8);
        assert_eq!(0x66_u8.to_channel_u8(), 0x66_u8);
        assert_eq!(0xA0_u8.to_channel_u8(), 0xA0_u8);
        assert_eq!(0xFF_u8.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x00_u8.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x30_u8.to_channel_u16(), 0x3030_u16);
        assert_eq!(0x66_u8.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xA0_u8.to_channel_u16(), 0xA0A0_u16);
        assert_eq!(0xFF_u8.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x00_u8.to_channel_f32(), 0f32);
        assert_eq!(0xFF_u8.to_channel_f32(), 1f32);

        assert_eq!(0x00_u8.to_channel_f64(), 0f64);
        assert_eq!(0xFF_u8.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u8() {
        assert_eq!(0x00_u8.invert_channel(), 0xFF_u8);
        assert_eq!(0x66_u8.invert_channel(), 0x99_u8);
        assert_eq!(0xFF_u8.invert_channel(), 0x00_u8);
    }

    #[test]
    fn test_to_channel_u16() {
        assert_eq!(0x0000_u16.to_channel_u8(), 0x00_u8);
        assert_eq!(0x3300_u16.to_channel_u8(), 0x33_u8);
        assert_eq!(0x6666_u16.to_channel_u8(), 0x66_u8);
        assert_eq!(0xAA00_u16.to_channel_u8(), 0xAA_u8);
        assert_eq!(0xFFFF_u16.to_channel_u8(), 0xFF_u8);

        assert_eq!(0x0000_u16.to_channel_u16(), 0x0000_u16);
        assert_eq!(0x3300_u16.to_channel_u16(), 0x3300_u16);
        assert_eq!(0x6666_u16.to_channel_u16(), 0x6666_u16);
        assert_eq!(0xAA00_u16.to_channel_u16(), 0xAA00_u16);
        assert_eq!(0xFFFF_u16.to_channel_u16(), 0xFFFF_u16);

        assert_eq!(0x0000_u16.to_channel_f32(), 0f32);
        assert_eq!(0xFFFF_u16.to_channel_f32(), 1f32);

        assert_eq!(0x0000_u16.to_channel_f64(), 0f64);
        assert_eq!(0xFFFF_u16.to_channel_f64(), 1f64);
    }

    #[test]
    fn test_invert_channel_u16() {
        assert_eq!(0x0000_u16.invert_channel(), 0xFFFF_u16);
        assert_eq!(0x6666_u16.invert_channel(), 0x9999_u16);
        assert_eq!(0xFFFF_u16.invert_channel(), 0x0000_u16);
    }

    #[test]
    fn test_to_channel_f32() {
        assert_eq!(0.00f32.to_channel_u8(), 0x00);
        assert_eq!(0.25f32.to_channel_u8(), 0x3F);
        assert_eq!(0.50f32.to_channel_u8(), 0x7F);
        assert_eq!(0.75f32.to_channel_u8(), 0xBF);
        assert_eq!(1.00f32.to_channel_u8(), 0xFF);

        assert_eq!(0.00f32.to_channel_u16(), 0x0000);
        assert_eq!(0.25f32.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f32.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f32.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f32.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f32.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f32.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f32.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f32.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f32() {
        assert_eq!(0.00f32.invert_channel(), 1.00f32);
        assert_eq!(0.50f32.invert_channel(), 0.50f32);
        assert_eq!(1.00f32.invert_channel(), 0.00f32);
    }

    #[test]
    fn test_invert_degrees_f32() {
        assert_eq!(  0.00f32.invert_degrees(), 180.00f32);
        assert_eq!( 45.00f32.invert_degrees(), 225.00f32);
        assert_eq!( 90.00f32.invert_degrees(), 270.00f32);
        assert_eq!(360.00f32.invert_degrees(), 180.00f32);
        assert_eq!(720.00f32.invert_degrees(), 180.00f32);
    }

    #[test]
    fn test_to_channel_f64() {
        assert_eq!(0.00f64.to_channel_u8(), 0x00);
        assert_eq!(0.25f64.to_channel_u8(), 0x3F);
        assert_eq!(0.50f64.to_channel_u8(), 0x7F);
        assert_eq!(0.75f64.to_channel_u8(), 0xBF);
        assert_eq!(1.00f64.to_channel_u8(), 0xFF);

        assert_eq!(0.00f64.to_channel_u16(), 0x0000);
        assert_eq!(0.25f64.to_channel_u16(), 0x3FFF);
        assert_eq!(0.50f64.to_channel_u16(), 0x7FFF);
        assert_eq!(0.75f64.to_channel_u16(), 0xBFFF);
        assert_eq!(1.00f64.to_channel_u16(), 0xFFFF);

        assert_eq!(0.00f64.to_channel_f32(), 0.00f32);
        assert_eq!(1.00f64.to_channel_f32(), 1.00f32);

        assert_eq!(0.00f64.to_channel_f64(), 0.00f64);
        assert_eq!(1.00f64.to_channel_f64(), 1.00f64);
    }

    #[test]
    fn test_invert_channel_f64() {
        assert_eq!(0.00f64.invert_channel(), 1.00f64);
        assert_eq!(0.50f64.invert_channel(), 0.50f64);
        assert_eq!(1.00f64.invert_channel(), 0.00f64);
    }

    #[test]
    fn test_invert_degrees_f64() {
        assert_eq!(  0.00f64.invert_degrees(), 180.00f64);
        assert_eq!( 45.00f64.invert_degrees(), 225.00f64);
        assert_eq!( 90.00f64.invert_degrees(), 270.00f64);
        assert_eq!(360.00f64.invert_degrees(), 180.00f64);
        assert_eq!(720.00f64.invert_degrees(), 180.00f64);
    }
}
<|endoftext|>