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

use std::net::SocketAddr;
use std::net::AddrParseError;
use std::result;
use std::sync::Arc;
use time::Duration;

use delix::logger;
use delix::node::{self, Node};
use delix::discovery::{Constant, Discovery};
use delix::relay::{self, Relay};
use delix::transport::{Direct, Transport, cipher};
use delix::transport::direct::{Balancer, balancer};
use configuration::Configuration;

#[derive(Debug)]
pub struct Loader {
    configuration: Configuration,
}

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    NoLogType,
    UnknownLogType(String),
    NoDiscoveryType,
    UnknownDiscoveryType(String),
    NoCipherType,
    UnknownCipherType(String),
    NoTransportType,
    UnknownTransportType(String),
    NoBalancerType,
    UnknownBalancerType(String),
    NoRelayType,
    UnknownRelayType(String),
    NoKey,
    NoAddress,
    NoName,
    NoLocalAddress,
    NodeError(node::Error),
    AddrParseError(AddrParseError),
    Cipher(cipher::Error),
    Relay(relay::Error),
}

impl Loader {
    pub fn new(configuration: Configuration) -> Loader {
        Loader { configuration: configuration }
    }

    pub fn load_log(&self) -> Result<()> {
        let log_type = match self.configuration.string_at("log.type") {
            Some(log_type) => log_type,
            None => return Err(Error::NoLogType),
        };

        match log_type.as_ref() {
            "console" => {
                logger::Console::init().unwrap();
                info!("loaded console log");
            }
            _ => return Err(Error::UnknownLogType(log_type)),
        }

        Ok(())
    }

    pub fn load_node(&self) -> Result<Arc<Node>> {
        let discovery_type = match self.configuration.string_at("discovery.type") {
            Some(discovery_type) => discovery_type,
            None => return Err(Error::NoDiscoveryType),
        };

        let discovery: Box<Discovery> = match discovery_type.as_ref() {
            "constant" => {
                let constant = Constant::new(try!(self.configuration
                                                      .strings_at("discovery.addresses")
                                                      .unwrap_or(vec![])
                                                      .iter()
                                                      .map(|s| s.parse::<SocketAddr>())
                                                      .collect()));
                info!("loaded constant discovery");
                Box::new(constant)
            }
            _ => return Err(Error::UnknownDiscoveryType(discovery_type)),
        };

        let cipher_type = match self.configuration.string_at("cipher.type") {
            Some(cipher_type) => cipher_type,
            None => return Err(Error::NoCipherType),
        };

        let cipher: Box<cipher::Cipher> = match cipher_type.as_ref() {
            "symmetric" => {
                let key = match self.configuration.bytes_at("cipher.key") {
                    Some(key) => key,
                    None => return Err(Error::NoKey),
                };
                let cipher = try!(cipher::Symmetric::new(&key, None));
                info!("loaded symmetric cipher");
                Box::new(cipher)
            }
            _ => return Err(Error::UnknownCipherType(cipher_type)),
        };

        let transport_type = match self.configuration.string_at("transport.type") {
            Some(transport_type) => transport_type,
            None => return Err(Error::NoTransportType),
        };

        let transport: Box<Transport> = match transport_type.as_ref() {
            "direct" => {
                let local_address = match self.configuration.string_at("transport.local_address") {
                    Some(local_address) => try!(local_address.parse::<SocketAddr>()),
                    None => return Err(Error::NoLocalAddress),
                };
                let public_address = match self.configuration
                                               .string_at("transport.public_address") {
                    Some(public_address) => Some(try!(public_address.parse::<SocketAddr>())),
                    None => None,
                };
                let request_timeout = self.configuration
                                          .i64_at("transport.request_timeout_ms")
                                          .map(|value| Duration::milliseconds(value));

                let balancer_type = match self.configuration.string_at("transport.balancer.type") {
                    Some(balancer_type) => balancer_type,
                    None => return Err(Error::NoBalancerType),
                };

                let balancer: Box<Balancer> = match balancer_type.as_ref() {
                    "dynamic_round_robin" => Box::new(balancer::DynamicRoundRobin::new()),
                    _ => return Err(Error::UnknownBalancerType(balancer_type)),
                };

                info!("loaded and bound direct transport to {}", local_address);

                Box::new(Direct::new(cipher,
                                     balancer,
                                     local_address,
                                     public_address,
                                     request_timeout))
            }
            _ => return Err(Error::UnknownTransportType(transport_type)),
        };

        Ok(Arc::new(try!(Node::new(discovery, transport))))
    }

    pub fn load_relays(&self, node: &Arc<Node>) -> Result<Vec<Box<Relay>>> {
        let mut relays = Vec::new();
        if let Some(configurations) = self.configuration.configurations_at("relay") {
            for configuration in configurations {
                let relay_type = match configuration.string_at("type") {
                    Some(relay_type) => relay_type,
                    None => return Err(Error::NoRelayType),
                };

                let relay: Box<Relay> = match relay_type.as_ref() {
                    "http_static" => {
                        let http_static = relay::HttpStatic::new(node.clone());
                        let address = match configuration.string_at("address") {
                            Some(address) => try!(address.parse::<SocketAddr>()),
                            None => return Err(Error::NoAddress),
                        };

                        if let Some(configurations) = configuration.configurations_at("service") {
                            for configuration in configurations {
                                let name = match configuration.string_at("name") {
                                    Some(name) => name,
                                    None => return Err(Error::NoName),
                                };
                                let address = match configuration.string_at("address") {
                                    Some(address) => try!(address.parse::<SocketAddr>()),
                                    None => return Err(Error::NoAddress),
                                };
                                http_static.add_service(&name, address);
                            }
                        }

                        try!(http_static.bind(address));

                        info!("loaded and bound http static relay to {}", address);

                        Box::new(http_static)
                    }
                    _ => return Err(Error::UnknownRelayType(relay_type)),
                };

                relays.push(relay);
            }

        }
        Ok(relays)
    }
}

impl From<node::Error> for Error {
    fn from(error: node::Error) -> Self {
        Error::NodeError(error)
    }
}

impl From<AddrParseError> for Error {
    fn from(error: AddrParseError) -> Self {
        Error::AddrParseError(error)
    }
}

impl From<cipher::Error> for Error {
    fn from(error: cipher::Error) -> Self {
        Error::Cipher(error)
    }
}

impl From<relay::Error> for Error {
    fn from(error: relay::Error) -> Self {
        Error::Relay(error)
    }
}
<commit_msg>made http static relay address optional<commit_after>// Copyright 2015 The Delix Project Authors. See the AUTHORS file at the top level directory.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use std::net::SocketAddr;
use std::net::AddrParseError;
use std::result;
use std::sync::Arc;
use time::Duration;

use delix::logger;
use delix::node::{self, Node};
use delix::discovery::{Constant, Discovery};
use delix::relay::{self, Relay};
use delix::transport::{Direct, Transport, cipher};
use delix::transport::direct::{Balancer, balancer};
use configuration::Configuration;

#[derive(Debug)]
pub struct Loader {
    configuration: Configuration,
}

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    NoLogType,
    UnknownLogType(String),
    NoDiscoveryType,
    UnknownDiscoveryType(String),
    NoCipherType,
    UnknownCipherType(String),
    NoTransportType,
    UnknownTransportType(String),
    NoBalancerType,
    UnknownBalancerType(String),
    NoRelayType,
    UnknownRelayType(String),
    NoKey,
    NoAddress,
    NoName,
    NoLocalAddress,
    NodeError(node::Error),
    AddrParseError(AddrParseError),
    Cipher(cipher::Error),
    Relay(relay::Error),
}

impl Loader {
    pub fn new(configuration: Configuration) -> Loader {
        Loader { configuration: configuration }
    }

    pub fn load_log(&self) -> Result<()> {
        let log_type = match self.configuration.string_at("log.type") {
            Some(log_type) => log_type,
            None => return Err(Error::NoLogType),
        };

        match log_type.as_ref() {
            "console" => {
                logger::Console::init().unwrap();
                info!("loaded console log");
            }
            _ => return Err(Error::UnknownLogType(log_type)),
        }

        Ok(())
    }

    pub fn load_node(&self) -> Result<Arc<Node>> {
        let discovery_type = match self.configuration.string_at("discovery.type") {
            Some(discovery_type) => discovery_type,
            None => return Err(Error::NoDiscoveryType),
        };

        let discovery: Box<Discovery> = match discovery_type.as_ref() {
            "constant" => {
                let constant = Constant::new(try!(self.configuration
                                                      .strings_at("discovery.addresses")
                                                      .unwrap_or(vec![])
                                                      .iter()
                                                      .map(|s| s.parse::<SocketAddr>())
                                                      .collect()));
                info!("loaded constant discovery");
                Box::new(constant)
            }
            _ => return Err(Error::UnknownDiscoveryType(discovery_type)),
        };

        let cipher_type = match self.configuration.string_at("cipher.type") {
            Some(cipher_type) => cipher_type,
            None => return Err(Error::NoCipherType),
        };

        let cipher: Box<cipher::Cipher> = match cipher_type.as_ref() {
            "symmetric" => {
                let key = match self.configuration.bytes_at("cipher.key") {
                    Some(key) => key,
                    None => return Err(Error::NoKey),
                };
                let cipher = try!(cipher::Symmetric::new(&key, None));
                info!("loaded symmetric cipher");
                Box::new(cipher)
            }
            _ => return Err(Error::UnknownCipherType(cipher_type)),
        };

        let transport_type = match self.configuration.string_at("transport.type") {
            Some(transport_type) => transport_type,
            None => return Err(Error::NoTransportType),
        };

        let transport: Box<Transport> = match transport_type.as_ref() {
            "direct" => {
                let local_address = match self.configuration.string_at("transport.local_address") {
                    Some(local_address) => try!(local_address.parse::<SocketAddr>()),
                    None => return Err(Error::NoLocalAddress),
                };
                let public_address = match self.configuration
                                               .string_at("transport.public_address") {
                    Some(public_address) => Some(try!(public_address.parse::<SocketAddr>())),
                    None => None,
                };
                let request_timeout = self.configuration
                                          .i64_at("transport.request_timeout_ms")
                                          .map(|value| Duration::milliseconds(value));

                let balancer_type = match self.configuration.string_at("transport.balancer.type") {
                    Some(balancer_type) => balancer_type,
                    None => return Err(Error::NoBalancerType),
                };

                let balancer: Box<Balancer> = match balancer_type.as_ref() {
                    "dynamic_round_robin" => Box::new(balancer::DynamicRoundRobin::new()),
                    _ => return Err(Error::UnknownBalancerType(balancer_type)),
                };

                info!("loaded direct transport - listening at {}", local_address);

                Box::new(Direct::new(cipher,
                                     balancer,
                                     local_address,
                                     public_address,
                                     request_timeout))
            }
            _ => return Err(Error::UnknownTransportType(transport_type)),
        };

        Ok(Arc::new(try!(Node::new(discovery, transport))))
    }

    pub fn load_relays(&self, node: &Arc<Node>) -> Result<Vec<Box<Relay>>> {
        let mut relays = Vec::new();
        if let Some(configurations) = self.configuration.configurations_at("relay") {
            for configuration in configurations {
                let relay_type = match configuration.string_at("type") {
                    Some(relay_type) => relay_type,
                    None => return Err(Error::NoRelayType),
                };

                let relay: Box<Relay> = match relay_type.as_ref() {
                    "http_static" => {
                        let http_static = relay::HttpStatic::new(node.clone());
                        let address = configuration.string_at("address");

                        if let Some(configurations) = configuration.configurations_at("service") {
                            for configuration in configurations {
                                let name = match configuration.string_at("name") {
                                    Some(name) => name,
                                    None => return Err(Error::NoName),
                                };
                                let address = match configuration.string_at("address") {
                                    Some(address) => try!(address.parse::<SocketAddr>()),
                                    None => return Err(Error::NoAddress),
                                };
                                http_static.add_service(&name, address);
                            }
                        }

                        if let Some(address) = address {
                            let address = try!(address.parse::<SocketAddr>());
                            try!(http_static.bind(address));
                            info!("loaded http static relay - listening at {}", address);
                        } else {
                            info!("loaded http static relay");
                        }

                        Box::new(http_static)
                    }
                    _ => return Err(Error::UnknownRelayType(relay_type)),
                };

                relays.push(relay);
            }

        }
        Ok(relays)
    }
}

impl From<node::Error> for Error {
    fn from(error: node::Error) -> Self {
        Error::NodeError(error)
    }
}

impl From<AddrParseError> for Error {
    fn from(error: AddrParseError) -> Self {
        Error::AddrParseError(error)
    }
}

impl From<cipher::Error> for Error {
    fn from(error: cipher::Error) -> Self {
        Error::Cipher(error)
    }
}

impl From<relay::Error> for Error {
    fn from(error: relay::Error) -> Self {
        Error::Relay(error)
    }
}
<|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 alloc::heap;
use freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules;
use freetype::freetype::FT_Done_Library;
use freetype::freetype::FT_Library;
use freetype::freetype::FT_Memory;
use freetype::freetype::FT_New_Library;
use freetype::freetype::struct_FT_MemoryRec_;
use libc::{c_long, c_void};
use std::ptr;
use std::rc::Rc;
use util::mem::{HeapSizeOf, heap_size_of};

// We pass a |User| struct -- via an opaque |void*| -- to FreeType each time a new instance is
// created. FreeType passes it back to the ft_alloc/ft_realloc/ft_free callbacks. We use it to
// record the memory usage of each FreeType instance.
struct User {
    size: usize,
}

// FreeType doesn't require any particular alignment for allocations.
const FT_ALIGNMENT: usize = 1;

extern fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void {
    unsafe {
        let ptr = heap::allocate(req_size as usize, FT_ALIGNMENT) as *mut c_void;
        let actual_size = heap_size_of(ptr);

        let user = (*mem).user as *mut User;
        (*user).size += actual_size;

        ptr
    }
}

extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) {
    unsafe {
        let actual_size = heap_size_of(ptr);

        let user = (*mem).user as *mut User;
        (*user).size -= actual_size;

        heap::deallocate(ptr as *mut u8, actual_size, FT_ALIGNMENT);
    }
}

extern fn ft_realloc(mem: FT_Memory, _cur_size: c_long, new_req_size: c_long,
                     old_ptr: *mut c_void) -> *mut c_void {
    unsafe {
        let old_actual_size = heap_size_of(old_ptr);
        let new_ptr = heap::reallocate(old_ptr as *mut u8, old_actual_size,
                                       new_req_size as usize, FT_ALIGNMENT) as *mut c_void;
        let new_actual_size = heap_size_of(new_ptr);

        let user = (*mem).user as *mut User;
        (*user).size += new_actual_size - old_actual_size;

        new_ptr
    }
}

// A |*mut User| field in a struct triggers a "use of `#[derive]` with a raw pointer" warning from
// rustc. But using a typedef avoids this, so...
pub type UserPtr = *mut User;

// WARNING: We need to be careful how we use this struct. See the comment about Rc<> in
// FontContextHandle.
#[derive(Clone)]
pub struct FreeTypeLibraryHandle {
    pub ctx: FT_Library,
    mem: FT_Memory,
    user: UserPtr,
}

impl Drop for FreeTypeLibraryHandle {
    fn drop(&mut self) {
        assert!(!self.ctx.is_null());
        unsafe {
            FT_Done_Library(self.ctx);
            Box::from_raw(self.mem);
            Box::from_raw(self.user);
        }
    }
}

impl HeapSizeOf for FreeTypeLibraryHandle {
    fn heap_size_of_children(&self) -> usize {
        let ft_size = unsafe { (*self.user).size };
        ft_size +
            heap_size_of(self.ctx as *const c_void) +
            heap_size_of(self.mem as *const c_void) +
            heap_size_of(self.user as *const c_void)
    }
}

#[derive(Clone, HeapSizeOf)]
pub struct FontContextHandle {
    // WARNING: FreeTypeLibraryHandle contains raw pointers, is clonable, and also implements
    // `Drop`. This field needs to be Rc<> to make sure that the `drop` function is only called
    // once, otherwise we'll get crashes. Yuk.
    pub ctx: Rc<FreeTypeLibraryHandle>,
}

impl FontContextHandle {
    pub fn new() -> FontContextHandle {
        let user = Box::into_raw(box User {
            size: 0,
        });
        let mem = Box::into_raw(box struct_FT_MemoryRec_ {
            user: user as *mut c_void,
            alloc: ft_alloc,
            free: ft_free,
            realloc: ft_realloc,
        });
        unsafe {
            let mut ctx: FT_Library = ptr::null_mut();

            let result = FT_New_Library(mem, &mut ctx);
            if !result.succeeded() { panic!("Unable to initialize FreeType library"); }

            FT_Add_Default_Modules(ctx);

            FontContextHandle {
                ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx, mem: mem, user: user }),
            }
        }
    }
}
<commit_msg>Avoid overflow in freetype/font_context.rs<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 alloc::heap;
use freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules;
use freetype::freetype::FT_Done_Library;
use freetype::freetype::FT_Library;
use freetype::freetype::FT_Memory;
use freetype::freetype::FT_New_Library;
use freetype::freetype::struct_FT_MemoryRec_;
use libc::{c_long, c_void};
use std::ptr;
use std::rc::Rc;
use util::mem::{HeapSizeOf, heap_size_of};

// We pass a |User| struct -- via an opaque |void*| -- to FreeType each time a new instance is
// created. FreeType passes it back to the ft_alloc/ft_realloc/ft_free callbacks. We use it to
// record the memory usage of each FreeType instance.
struct User {
    size: usize,
}

// FreeType doesn't require any particular alignment for allocations.
const FT_ALIGNMENT: usize = 1;

extern fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void {
    unsafe {
        let ptr = heap::allocate(req_size as usize, FT_ALIGNMENT) as *mut c_void;
        let actual_size = heap_size_of(ptr);

        let user = (*mem).user as *mut User;
        (*user).size += actual_size;

        ptr
    }
}

extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) {
    unsafe {
        let actual_size = heap_size_of(ptr);

        let user = (*mem).user as *mut User;
        (*user).size -= actual_size;

        heap::deallocate(ptr as *mut u8, actual_size, FT_ALIGNMENT);
    }
}

extern fn ft_realloc(mem: FT_Memory, _cur_size: c_long, new_req_size: c_long,
                     old_ptr: *mut c_void) -> *mut c_void {
    unsafe {
        let old_actual_size = heap_size_of(old_ptr);
        let new_ptr = heap::reallocate(old_ptr as *mut u8, old_actual_size,
                                       new_req_size as usize, FT_ALIGNMENT) as *mut c_void;
        let new_actual_size = heap_size_of(new_ptr);

        let user = (*mem).user as *mut User;
        (*user).size += new_actual_size;
        (*user).size -= old_actual_size;

        new_ptr
    }
}

// A |*mut User| field in a struct triggers a "use of `#[derive]` with a raw pointer" warning from
// rustc. But using a typedef avoids this, so...
pub type UserPtr = *mut User;

// WARNING: We need to be careful how we use this struct. See the comment about Rc<> in
// FontContextHandle.
#[derive(Clone)]
pub struct FreeTypeLibraryHandle {
    pub ctx: FT_Library,
    mem: FT_Memory,
    user: UserPtr,
}

impl Drop for FreeTypeLibraryHandle {
    fn drop(&mut self) {
        assert!(!self.ctx.is_null());
        unsafe {
            FT_Done_Library(self.ctx);
            Box::from_raw(self.mem);
            Box::from_raw(self.user);
        }
    }
}

impl HeapSizeOf for FreeTypeLibraryHandle {
    fn heap_size_of_children(&self) -> usize {
        let ft_size = unsafe { (*self.user).size };
        ft_size +
            heap_size_of(self.ctx as *const c_void) +
            heap_size_of(self.mem as *const c_void) +
            heap_size_of(self.user as *const c_void)
    }
}

#[derive(Clone, HeapSizeOf)]
pub struct FontContextHandle {
    // WARNING: FreeTypeLibraryHandle contains raw pointers, is clonable, and also implements
    // `Drop`. This field needs to be Rc<> to make sure that the `drop` function is only called
    // once, otherwise we'll get crashes. Yuk.
    pub ctx: Rc<FreeTypeLibraryHandle>,
}

impl FontContextHandle {
    pub fn new() -> FontContextHandle {
        let user = Box::into_raw(box User {
            size: 0,
        });
        let mem = Box::into_raw(box struct_FT_MemoryRec_ {
            user: user as *mut c_void,
            alloc: ft_alloc,
            free: ft_free,
            realloc: ft_realloc,
        });
        unsafe {
            let mut ctx: FT_Library = ptr::null_mut();

            let result = FT_New_Library(mem, &mut ctx);
            if !result.succeeded() { panic!("Unable to initialize FreeType library"); }

            FT_Add_Default_Modules(ctx);

            FontContextHandle {
                ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx, mem: mem, user: user }),
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// The standard logging macro.
///
/// This macro will generically log with the specified `Level` and `format!`
/// based argument list.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// use log::Level;
///
/// # fn main() {
/// let data = (42, "Forty-two");
/// let private_data = "private";
///
/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
///     data.0, data.1, private_data);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            $crate::__private_api_log(
                __log_format_args!($($arg)+),
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
            );
        }
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))
}

/// Logs a message at the error level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// let (err_info, port) = ("No connection", 22);
///
/// error!("Error: {} on port {}", err_info, port);
/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Error, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Error, $($arg)*);
    )
}

/// Logs a message at the warn level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// let warn_description = "Invalid Input";
///
/// warn!("Warning! {}!", warn_description);
/// warn!(target: "input_events", "App received warning: {}", warn_description);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Warn, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Warn, $($arg)*);
    )
}

/// Logs a message at the info level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// # struct Connection { port: u32, speed: f32 }
/// let conn_info = Connection { port: 40, speed: 3.20 };
///
/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
///       conn_info.port, conn_info.speed);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Info, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Info, $($arg)*);
    )
}

/// Logs a message at the debug level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Debug, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Debug, $($arg)*);
    )
}

/// Logs a message at the trace level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
/// trace!(target: "app_events", "x is {} and y is {}",
///        if pos.x >= 0.0 { "positive" } else { "negative" },
///        if pos.y >= 0.0 { "positive" } else { "negative" });
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Trace, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Trace, $($arg)*);
    )
}

/// Determines if a message logged at the specified level in that module will
/// be logged.
///
/// This can be used to avoid expensive computation of log message arguments if
/// the message would be ignored anyway.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// use log::Level::Debug;
///
/// # fn foo() {
/// if log_enabled!(Debug) {
///     let data = expensive_call();
///     debug!("expensive debug data: {} {}", data.x, data.y);
/// }
/// if log_enabled!(target: "Global", Debug) {
///    let data = expensive_call();
///    debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
/// }
/// # }
/// # struct Data { x: u32, y: u32 }
/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! log_enabled {
    (target: $target:expr, $lvl:expr) => {{
        let lvl = $lvl;
        lvl <= $crate::STATIC_MAX_LEVEL
            && lvl <= $crate::max_level()
            && $crate::__private_api_enabled(lvl, $target)
    }};
    ($lvl:expr) => {
        log_enabled!(target: __log_module_path!(), $lvl)
    };
}

// The log macro above cannot invoke format_args directly because it uses
// local_inner_macros. A format_args invocation there would resolve to
// $crate::format_args which does not exist. Instead invoke format_args here
// outside of local_inner_macros so that it resolves (probably) to
// core::format_args or std::format_args. Same for the several macros that
// follow.
//
// This is a workaround until we drop support for pre-1.30 compilers. At that
// point we can remove use of local_inner_macros, use $crate:: when invoking
// local macros, and invoke format_args directly.
#[doc(hidden)]
#[macro_export]
macro_rules! __log_format_args {
    ($($args:tt)*) => {
        format_args!($($args)*)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_module_path {
    () => {
        module_path!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_file {
    () => {
        file!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_line {
    () => {
        line!()
    };
}
<commit_msg>Fix so log_enabled can be used without #[macro_use]<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// The standard logging macro.
///
/// This macro will generically log with the specified `Level` and `format!`
/// based argument list.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// use log::Level;
///
/// # fn main() {
/// let data = (42, "Forty-two");
/// let private_data = "private";
///
/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
///     data.0, data.1, private_data);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            $crate::__private_api_log(
                __log_format_args!($($arg)+),
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
            );
        }
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))
}

/// Logs a message at the error level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// let (err_info, port) = ("No connection", 22);
///
/// error!("Error: {} on port {}", err_info, port);
/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Error, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Error, $($arg)*);
    )
}

/// Logs a message at the warn level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// let warn_description = "Invalid Input";
///
/// warn!("Warning! {}!", warn_description);
/// warn!(target: "input_events", "App received warning: {}", warn_description);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Warn, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Warn, $($arg)*);
    )
}

/// Logs a message at the info level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// # struct Connection { port: u32, speed: f32 }
/// let conn_info = Connection { port: 40, speed: 3.20 };
///
/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
///       conn_info.port, conn_info.speed);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Info, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Info, $($arg)*);
    )
}

/// Logs a message at the debug level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Debug, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Debug, $($arg)*);
    )
}

/// Logs a message at the trace level.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
/// trace!(target: "app_events", "x is {} and y is {}",
///        if pos.x >= 0.0 { "positive" } else { "negative" },
///        if pos.y >= 0.0 { "positive" } else { "negative" });
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
    (target: $target:expr, $($arg:tt)*) => (
        log!(target: $target, $crate::Level::Trace, $($arg)*);
    );
    ($($arg:tt)*) => (
        log!($crate::Level::Trace, $($arg)*);
    )
}

/// Determines if a message logged at the specified level in that module will
/// be logged.
///
/// This can be used to avoid expensive computation of log message arguments if
/// the message would be ignored anyway.
///
/// # Examples
///
/// ```rust
/// # #[macro_use]
/// # extern crate log;
/// use log::Level::Debug;
///
/// # fn foo() {
/// if log_enabled!(Debug) {
///     let data = expensive_call();
///     debug!("expensive debug data: {} {}", data.x, data.y);
/// }
/// if log_enabled!(target: "Global", Debug) {
///    let data = expensive_call();
///    debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
/// }
/// # }
/// # struct Data { x: u32, y: u32 }
/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log_enabled {
    (target: $target:expr, $lvl:expr) => {{
        let lvl = $lvl;
        lvl <= $crate::STATIC_MAX_LEVEL
            && lvl <= $crate::max_level()
            && $crate::__private_api_enabled(lvl, $target)
    }};
    ($lvl:expr) => {
        log_enabled!(target: __log_module_path!(), $lvl)
    };
}

// The log macro above cannot invoke format_args directly because it uses
// local_inner_macros. A format_args invocation there would resolve to
// $crate::format_args which does not exist. Instead invoke format_args here
// outside of local_inner_macros so that it resolves (probably) to
// core::format_args or std::format_args. Same for the several macros that
// follow.
//
// This is a workaround until we drop support for pre-1.30 compilers. At that
// point we can remove use of local_inner_macros, use $crate:: when invoking
// local macros, and invoke format_args directly.
#[doc(hidden)]
#[macro_export]
macro_rules! __log_format_args {
    ($($args:tt)*) => {
        format_args!($($args)*)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_module_path {
    () => {
        module_path!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_file {
    () => {
        file!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_line {
    () => {
        line!()
    };
}
<|endoftext|>


<commit_before>/* This is to work around a false positive for the clippy warning
 * `match_on_same_arms`.
 * See https://github.com/Manishearth/rust-clippy/issues/1390
 */
#[cfg(not(html_trace))]
#[inline(always)]
pub fn nop() {}

#[cfg(html_trace)]
#[macro_export]
macro_rules! html_trace {
    ($fmt:expr) => {
         let bt = ::backtrace::Backtrace::new();
         println!( concat!($fmt, " at {:?}"), bt );
    };
    ($fmt:expr, $( $args:expr ),*) => {
         let bt = ::backtrace::Backtrace::new();
         println!( concat!($fmt, " at {:?}"), $( $args ),* , bt );
    };
}
#[cfg(not(html_trace))]
#[macro_export]
macro_rules! html_trace {
    ($fmt:expr) => { $crate::macros::nop(); };
    ($fmt:expr, $( $args:expr ),*) => { $crate::macros::nop(); };
}

#[cfg(html_trace)]
#[macro_export]
macro_rules! html_trace_quiet {
    ($fmt:expr) => {
         println!( $fmt );
    };
    ($fmt:expr, $( $args:expr ),*) => {
         println!( $fmt, $( $args ),* );
    };
}

#[cfg(not(html_trace))]
#[macro_export]
macro_rules! html_trace_quiet {
    ($fmt:expr) => { $crate::macros::nop(); };
    ($fmt:expr, $( $args:expr ),*) => { $crate::macros::nop(); };
}
<commit_msg>Hide the trace macros from the documentation.<commit_after>/* This is to work around a false positive for the clippy warning
 * `match_on_same_arms`.
 * See https://github.com/Manishearth/rust-clippy/issues/1390
 */
#[cfg(not(html_trace))]
#[inline(always)]
pub fn nop() {}

#[cfg(html_trace)]
#[macro_export]
#[doc(hidden)]
macro_rules! html_trace {
    ($fmt:expr) => {
         let bt = ::backtrace::Backtrace::new();
         println!( concat!($fmt, " at {:?}"), bt );
    };
    ($fmt:expr, $( $args:expr ),*) => {
         let bt = ::backtrace::Backtrace::new();
         println!( concat!($fmt, " at {:?}"), $( $args ),* , bt );
    };
}
#[cfg(not(html_trace))]
#[macro_export]
#[doc(hidden)]
macro_rules! html_trace {
    ($fmt:expr) => { $crate::macros::nop(); };
    ($fmt:expr, $( $args:expr ),*) => { $crate::macros::nop(); };
}

#[cfg(html_trace)]
#[macro_export]
#[doc(hidden)]
macro_rules! html_trace_quiet {
    ($fmt:expr) => {
         println!( $fmt );
    };
    ($fmt:expr, $( $args:expr ),*) => {
         println!( $fmt, $( $args ),* );
    };
}

#[cfg(not(html_trace))]
#[macro_export]
#[doc(hidden)]
macro_rules! html_trace_quiet {
    ($fmt:expr) => { $crate::macros::nop(); };
    ($fmt:expr, $( $args:expr ),*) => { $crate::macros::nop(); };
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub enum IntToEnumError {
    InvalidU8(u8),
    InvalidU16(u16),
}

/// Named curves, as defined in [RFC4492] and [RFC7027]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u16)]
pub enum NamedCurve {
    Sect163k1 = 1,
    Sect163r1 = 2,
    Sect163r2 = 3,
    Sect193r1 = 4,
    Sect193r2 = 5,
    Sect233k1 = 6,
    Sect233r1 = 7,
    Sect239k1 = 8,
    Sect283k1 = 9,
    Sect283r1 = 10,
    Sect409k1 = 11,
    Sect409r1 = 12,
    Sect571k1 = 13,
    Sect571r1 = 14,
    Secp160k1 = 15,
    Secp160r1 = 16,
    Secp160r2 = 17,
    Secp192k1 = 18,
    Secp192r1 = 19,
    Secp224k1 = 20,
    Secp224r1 = 21,
    Secp256k1 = 22,
    Secp256r1 = 23,
    Secp384r1 = 24,
    Secp521r1 = 25,
    BrainpoolP256r1 = 26,
    BrainpoolP384r1 = 27,
    BrainpoolP512r1 = 28,
    ArbitraryExplicitPrimeCurves = 0xFF01,
    ArbitraryExplicitChar2Curves = 0xFF02,
}
}

/// Hash algorithms, as defined in [RFC5246]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u8)]
pub enum HashAlgorithm {
    None = 0,
    Md5 = 1,
    Sh1 = 2,
    Sha224 = 3,
    Sha256 = 4,
    Sha384 = 5,
    Sha512 = 6,
}
}

/// Signature algorithms, as defined in [RFC5246]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u8)]
pub enum SignatureAlgorithm {
    Anonymous = 0,
    Rsa = 1,
    Dsa = 2,
    Ecdsa = 3,
}
}

#[macro_export]
macro_rules! error_if (
  ($i:expr, $cond:expr, $err:expr) => (
    {
      if $cond {
        IResult::Error($err)
      } else {
        IResult::Done($i, ())
      }
    }
  );
  ($i:expr, $cond:expr, $err:expr) => (
    error!($i, $cond, $err);
  );
);

pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> {
    let mut u = 0;

    for &c in s {
        u *= 256;
        u += c as u64;
    }

    Ok(u)
}

#[macro_use]
macro_rules! parse_hex_to_u64 (
    ( $i:expr, $size:expr ) => (
        map_res!($i, take!(($size as usize)), $crate::bytes_to_u64)
    );
);

#[macro_use]
named!(pub parse_uint24<&[u8], u64>, parse_hex_to_u64!(3));

//named!(parse_hex4<&[u8], u64>, parse_hex_to_u64!(4));
<commit_msg>Fix typo<commit_after>#[derive(Debug)]
pub enum IntToEnumError {
    InvalidU8(u8),
    InvalidU16(u16),
}

/// Named curves, as defined in [RFC4492] and [RFC7027]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u16)]
pub enum NamedCurve {
    Sect163k1 = 1,
    Sect163r1 = 2,
    Sect163r2 = 3,
    Sect193r1 = 4,
    Sect193r2 = 5,
    Sect233k1 = 6,
    Sect233r1 = 7,
    Sect239k1 = 8,
    Sect283k1 = 9,
    Sect283r1 = 10,
    Sect409k1 = 11,
    Sect409r1 = 12,
    Sect571k1 = 13,
    Sect571r1 = 14,
    Secp160k1 = 15,
    Secp160r1 = 16,
    Secp160r2 = 17,
    Secp192k1 = 18,
    Secp192r1 = 19,
    Secp224k1 = 20,
    Secp224r1 = 21,
    Secp256k1 = 22,
    Secp256r1 = 23,
    Secp384r1 = 24,
    Secp521r1 = 25,
    BrainpoolP256r1 = 26,
    BrainpoolP384r1 = 27,
    BrainpoolP512r1 = 28,
    ArbitraryExplicitPrimeCurves = 0xFF01,
    ArbitraryExplicitChar2Curves = 0xFF02,
}
}

/// Hash algorithms, as defined in [RFC5246]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u8)]
pub enum HashAlgorithm {
    None = 0,
    Md5 = 1,
    Sha1 = 2,
    Sha224 = 3,
    Sha256 = 4,
    Sha384 = 5,
    Sha512 = 6,
}
}

/// Signature algorithms, as defined in [RFC5246]
enum_from_primitive! {
#[derive(Debug)]
#[repr(u8)]
pub enum SignatureAlgorithm {
    Anonymous = 0,
    Rsa = 1,
    Dsa = 2,
    Ecdsa = 3,
}
}

#[macro_export]
macro_rules! error_if (
  ($i:expr, $cond:expr, $err:expr) => (
    {
      if $cond {
        IResult::Error($err)
      } else {
        IResult::Done($i, ())
      }
    }
  );
  ($i:expr, $cond:expr, $err:expr) => (
    error!($i, $cond, $err);
  );
);

pub fn bytes_to_u64(s: &[u8]) -> Result<u64, &'static str> {
    let mut u = 0;

    for &c in s {
        u *= 256;
        u += c as u64;
    }

    Ok(u)
}

#[macro_use]
macro_rules! parse_hex_to_u64 (
    ( $i:expr, $size:expr ) => (
        map_res!($i, take!(($size as usize)), $crate::bytes_to_u64)
    );
);

#[macro_use]
named!(pub parse_uint24<&[u8], u64>, parse_hex_to_u64!(3));

//named!(parse_hex4<&[u8], u64>, parse_hex_to_u64!(4));
<|endoftext|>


<commit_before>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinators Y and Z](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the thrush (reverse application) combinator T

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(i().app(zero()), &Normal), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(app!(k(), zero(), one()), &Normal), zero());
/// # }
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(app!(s(), 0.into(), 1.into(), 2.into()), &Normal),
///            beta_full(app!(Term::from(0), 2.into(), app!(Term::from(1), 2.into())), &Normal)
/// );
/// # }
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), app(Var(2), Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(app!(iota(), iota()), &Normal), i());
/// assert_eq!(beta_full(app!(iota(), app!(iota(), app!(iota(), iota()))), &Normal), k());
/// assert_eq!(beta_full(app!(iota(), app!(iota(), app!(iota(), app!(iota(), iota())))), &Normal),
///            s());
/// # }
/// ```
pub fn iota() -> Term { abs(app!(Var(1), s(), k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(app!(b(), 0.into(), 1.into(), 2.into()), &Normal),
///            beta_full(app!(Term::from(0), app!(Term::from(1), 2.into())), &Normal)
/// );
/// # }
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        app(Var(3), app(Var(2), Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(app!(c(), 0.into(), 1.into(), 2.into()), &Normal),
///            beta_full(app!(Term::from(0), 2.into(), 1.into()), &Normal)
/// );
/// # }
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(app!(w(), zero(), one()), &Normal),
///            beta_full(app!(zero(), one(), one()), &Normal)
/// );
/// # }
/// ```
pub fn w() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(om().app(zero()), &Normal), beta_full(zero().app(zero()), &Normal));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::reduction::beta_once;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_once(omm(), &Normal), omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the lazy fixed-point combinator intended for the `Normal` evaluation `Order`.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(y().app(zero()), &Normal),
///            beta_full(app!(zero(), app!(y(), zero())), &Normal)
/// );
/// # }
/// ```
pub fn y() -> Term {
    abs(app(
        abs(app(Var(2), app(Var(1), Var(1)))),
        abs(app(Var(2), app(Var(1), Var(1))))
    ))
}

/// Z - the strict fixed-point combinator intended for the `CallByValue` evaluation `Order`.
///
/// Z := λf.(λx.f (λv.x x v)) (λx.f (λv.x x v)) = λ (λ 2 (λ 2 2 1)) (λ 2 (λ 2 2 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::z;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta_full;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta_full(z().app(zero()), &CallByValue),
///            beta_full(app!(zero(), app!(z(), zero())), &CallByValue)
/// );
/// # }
/// ```
pub fn z() -> Term {
    abs(app(
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1))))),
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1)))))
    ))
}

/// T - the thrush combinator
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::arithmetic::{zero, one};
///
/// assert_eq!(t().apply(&zero()).and_then(|t| t.apply(&one())), Ok(one().app(zero())));
/// ```
pub fn t() -> Term {
    abs(abs(
        app(Var(1), Var(2))
    ))
}
<commit_msg>migrate combinators to the new beta<commit_after>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinators Y and Z](https://en.wikipedia.org/wiki/Fixed-point_combinator)
//! * the thrush (reverse application) combinator T

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(i().app(zero()), &Normal, None), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = TRUE
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(k(), zero(), one()), &Normal, None), zero());
/// # }
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(s(), 0.into(), 1.into(), 2.into()), &Normal, None),
///            beta(app!(Term::from(0), 2.into(), app!(Term::from(1), 2.into())), &Normal, None)
/// );
/// # }
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), app(Var(2), Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(iota(), iota()), &Normal, None), i());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), iota()))), &Normal, None), k());
/// assert_eq!(beta(app!(iota(), app!(iota(), app!(iota(), app!(iota(), iota())))), &Normal, None),
///            s());
/// # }
/// ```
pub fn iota() -> Term { abs(app!(Var(1), s(), k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(b(), 0.into(),           1.into(), 2.into() ), &Normal, None),
///            beta(app!(Term::from(0), app!(Term::from(1), 2.into())), &Normal, None)
/// );
/// # }
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        app(Var(3), app(Var(2), Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(c(), 0.into(), 1.into(), 2.into()), &Normal, None),
///            beta(app!(Term::from(0), 2.into(), 1.into()), &Normal, None)
/// );
/// # }
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(1), Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(   w(), zero(), one()), &Normal, None),
///            beta(app!(zero(),  one(), one()), &Normal, None)
/// );
/// # }
/// ```
pub fn w() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x = λ 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(  om().app(zero()), &Normal, None),
///            beta(zero().app(zero()), &Normal, None)
/// );
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
/// ```
/// use lambda_calculus::combinators::omm;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(omm(), &Normal, Some(3)), omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the lazy fixed-point combinator intended for the `Normal` evaluation `Order`.
///
/// Y := λf.(λx.f (x x)) (λx.f (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(             app!(y(), zero() ), &Normal, None),
///            beta(app!(zero(), app!(y(), zero())), &Normal, None)
/// );
/// # }
/// ```
pub fn y() -> Term {
    abs(app(
        abs(app(Var(2), app(Var(1), Var(1)))),
        abs(app(Var(2), app(Var(1), Var(1))))
    ))
}

/// Z - the strict fixed-point combinator intended for the `CallByValue` evaluation `Order`.
///
/// Z := λf.(λx.f (λv.x x v)) (λx.f (λv.x x v)) = λ (λ 2 (λ 2 2 1)) (λ 2 (λ 2 2 1))
///
/// # Example
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::combinators::z;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(             app!(z(), zero()) , &CallByValue, None),
///            beta(app!(zero(), app!(z(), zero())), &CallByValue, None)
/// );
/// # }
/// ```
pub fn z() -> Term {
    abs(app(
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1))))),
        abs(app(Var(2), abs(app!(Var(2), Var(2), Var(1)))))
    ))
}

/// T - the thrush combinator
///
/// T := λxf. f x = λ λ 1 2
///
/// # Example
/// ```
/// use lambda_calculus::combinators::t;
/// use lambda_calculus::arithmetic::{zero, one};
///
/// assert_eq!(t().apply(&zero()).and_then(|t| t.apply(&one())), Ok(one().app(zero())));
/// ```
pub fn t() -> Term {
    abs(abs(
        app(Var(1), Var(2))
    ))
}
<|endoftext|>


<commit_before>// xfail-test FIXME Blocked on (#3585)

extern mod std;

// These tests used to be separate files, but I wanted to refactor all
// the common code.

use cmp::Eq;
use std::ebml2;
use io::Writer;
use std::serialization2::{Serializer, Serializable, deserialize};
use std::prettyprint2;

fn test_ser_and_deser<A:Eq Serializable>(
    a1: A,
    expected: ~str
) {
    // check the pretty printer:
    let s = do io::with_str_writer |w| {
        a1.serialize(&prettyprint2::Serializer(w))
    };
    debug!("s == %?", s);
    assert s == expected;

    // check the EBML serializer:
    let bytes = do io::with_bytes_writer |wr| {
        let ebml_w = &ebml2::Serializer(wr);
        a1.serialize(ebml_w)
    };
    let d = ebml2::Doc(@bytes);
    let a2: A = deserialize(&ebml2::Deserializer(d));
    assert a1 == a2;
}

#[auto_serialize2]
enum Expr {
    Val(uint),
    Plus(@Expr, @Expr),
    Minus(@Expr, @Expr)
}

impl Expr : cmp::Eq {
    pure fn eq(other: &Expr) -> bool {
        match self {
            Val(e0a) => {
                match *other {
                    Val(e0b) => e0a == e0b,
                    _ => false
                }
            }
            Plus(e0a, e1a) => {
                match *other {
                    Plus(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
            Minus(e0a, e1a) => {
                match *other {
                    Minus(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
        }
    }
    pure fn ne(other: &Expr) -> bool { !self.eq(other) }
}

fn main() {
    test_ser_and_deser(Plus(@Minus(@Val(3u), @Val(10u)),
                            @Plus(@Val(22u), @Val(5u))),
                       ~"Plus(@Minus(@Val(3u), @Val(10u)), \
                        @Plus(@Val(22u), @Val(5u)))");
}
<commit_msg>test: un-xfail the auto_serialize for boxes test<commit_after>extern mod std;

// These tests used to be separate files, but I wanted to refactor all
// the common code.

use cmp::Eq;
use std::ebml2;
use io::Writer;
use std::serialization2::{Serializer, Serializable, deserialize};
use std::prettyprint2;

fn test_ser_and_deser<A:Eq Serializable>(
    a1: A,
    expected: ~str
) {
    // check the pretty printer:
    let s = do io::with_str_writer |w| {
        a1.serialize(&prettyprint2::Serializer(w))
    };
    debug!("s == %?", s);
    assert s == expected;

    // check the EBML serializer:
    let bytes = do io::with_bytes_writer |wr| {
        let ebml_w = &ebml2::Serializer(wr);
        a1.serialize(ebml_w)
    };
    let d = ebml2::Doc(@bytes);
    let a2: A = deserialize(&ebml2::Deserializer(d));
    assert a1 == a2;
}

#[auto_serialize2]
enum Expr {
    Val(uint),
    Plus(@Expr, @Expr),
    Minus(@Expr, @Expr)
}

impl Expr : cmp::Eq {
    pure fn eq(other: &Expr) -> bool {
        match self {
            Val(e0a) => {
                match *other {
                    Val(e0b) => e0a == e0b,
                    _ => false
                }
            }
            Plus(e0a, e1a) => {
                match *other {
                    Plus(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
            Minus(e0a, e1a) => {
                match *other {
                    Minus(e0b, e1b) => e0a == e0b && e1a == e1b,
                    _ => false
                }
            }
        }
    }
    pure fn ne(other: &Expr) -> bool { !self.eq(other) }
}

fn main() {
    test_ser_and_deser(Plus(@Minus(@Val(3u), @Val(10u)),
                            @Plus(@Val(22u), @Val(5u))),
                       ~"Plus(@Minus(@Val(3u), @Val(10u)), \
                        @Plus(@Val(22u), @Val(5u)))");
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//

use memory::PAddr;
use super::{Address, Allocator, AllocErr, Layout};

/// A simple bump pointer allocator.
///
/// This allocator has few "moving parts" and is very fast. However, it doesn't
/// allow objects to be deallocated. We use this allocator for early kernel
/// objects before we can set up a more sophisticated heap allocator.
#[derive(Debug)]
pub struct BumpPtr { start: PAddr
                   , end: PAddr
                   , ptr: *mut u8
                   }

impl BumpPtr {
    pub const fn new(start: PAddr, end: PAddr) -> Self {
        BumpPtr { start: start
                , end: end
                , ptr: start.as_mut_ptr()
                }
    }
}

unsafe impl Allocator for BumpPtr {
    unsafe fn alloc(&mut self, layout: Layout) -> Result<Address, AllocErr> {
        unimplemented!()
    }
    unsafe fn dealloc(&mut self, ptr: Address, layout: Layout) {
        // just leak it
    }
}
<commit_msg>[alloc] working bump pointer impl<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//

use memory::{Addr, PAddr};
use super::{Address, Allocator, AllocErr, Layout};

/// A simple bump pointer allocator.
///
/// This allocator has few "moving parts" and is very fast. However, it doesn't
/// allow objects to be deallocated. We use this allocator for early kernel
/// objects before we can set up a more sophisticated heap allocator.
#[derive(Debug)]
pub struct BumpPtr { start: PAddr
                   , end: PAddr
                   , ptr: PAddr
                   }

impl BumpPtr {
    pub const fn new(start: PAddr, end: PAddr) -> Self {
        BumpPtr { start: start
                , end: end
                , ptr: start
                }
    }
}

unsafe impl Allocator for BumpPtr {
    unsafe fn alloc(&mut self, layout: Layout) -> Result<Address, AllocErr> {
        let start = self.ptr.align_up(layout.align() as <PAddr as Addr>::Repr);
        // TODO: can this be a saturating add?
        let end = start + layout.size() as <PAddr as Addr>::Repr;
        if end > self.end {
            Err(AllocErr::Exhausted{ request: layout.clone() })
        } else {
            // bump
            self.ptr = end;
            Ok(start.as_mut_ptr())
        }
    }
    unsafe fn dealloc(&mut self, ptr: Address, layout: Layout) {
        // just leak it
    }
}
<|endoftext|>


<commit_before>// This module loads the configuration file

use dailyschedule::{DailyEvent, Filter, Moment};
use std::convert::Into;
use std::error;
use std::fmt;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::path;
use std::result;
use time::{Duration, at_utc};
use toml;
use daylight::calculate_daylight;

const CONFIG_HEAD: &'static str = "config";
const CONFIG_DEVICE: &'static str = "device";
const CONFIG_LATITUDE: &'static str = "latitude";
const CONFIG_LONGITUDE: &'static str = "longitude";
const CONFIG_NTP_SERVER: &'static str = "ntp";
const CIRCLE_MAC: &'static str = "mac";
const CIRCLE_DEFAULT: &'static str = "default";

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    MissingEventSpecifier(String),
    WrongEventSpecifier(String),
    MissingStartEvent(String),
    MissingEndEvent(String),
    ScheduleExpected(String),
    InvalidMac(String),
    InvalidDefault(String),
    MissingNTP,
    LocationMissing,
    InvalidToml,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref err) => fmt::Display::fmt(err, f),
            _ => write!(f, "Keeper configuraton error"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => error::Error::description(err),
            _ => "Keeper configuration error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref err) => err.cause(),
            _ => None,
        }
    }
}

#[derive(Debug)]
pub enum Event {
    Fixed(u8, u8),
    Fuzzy((u8, u8), (u8, u8)),
    Sunrise(u16),
    Sunset(u16)
}

impl Event {
    fn time_in_a_day(value: &toml::Value) -> Option<(u8, u8)> {
        let mapped: Option<Vec<i64>> = value.as_slice()
                                            .map(|arr| arr.iter()
                                                          .filter_map(|x|x.as_integer())
                                                          .collect());
        mapped.map_or(None, |v| {
            match v.len() {
                2 => {
                    let (h,m) = (v[0], v[1]);
                    if h < 0 || h >= 48 {
                        None
                    } else if m < 0 || m >= 60 {
                        None
                    } else {
                        Some((h as u8, m as u8))
                    }
                },
                _ => None
            }
        })
    }

    fn new(key: &str, value: &toml::Value) -> Result<Event> {
        let specifier = try!(key.split("_").last().ok_or(
                Error::MissingEventSpecifier(key.into())));

        match specifier {
            "fixed" => Event::time_in_a_day(value).map(|(f,s)| Event::Fixed(f,s)).ok_or(
                Error::WrongEventSpecifier("fixed must hold a array of two integers".into())),
            "fuzzy" => value.as_slice().map_or(None, |s| {
                    match s.len() {
                        2 => {
                            let first = Event::time_in_a_day(&s[0]);
                            let second = Event::time_in_a_day(&s[1]);
                            first.map_or(None, |f| second.map(|s| Event::Fuzzy(f,s)))
                        },
                        _ => None
                    }
                }).ok_or(Error::WrongEventSpecifier("fuzzy must hold a array of two arrays of two integers".into())),
            "sunrise" => value.as_integer().map(|i| Event::Sunrise(i as u16)).ok_or(
                Error::WrongEventSpecifier("sunrise must only hold one integer (variance in minutes)".into())),
            "sunset" => value.as_integer().map(|i| Event::Sunset(i as u16)).ok_or(
                Error::WrongEventSpecifier("sunset must only hold one integer (variance in minutes)".into())),
            _ => Err(Error::WrongEventSpecifier("unsupported specifier".into()))
        }
    }

    pub fn into_dailyevent(&self, device: &Device) -> DailyEvent {
        let latitude = device.latitude;
        let longitude = device.longitude;
        match self {
            &Event::Fixed(h,m) => DailyEvent::Fixed(Filter::Always, Moment::new(h,m,0)),
            &Event::Fuzzy((h1,m1),(h2,m2)) =>
                DailyEvent::Fuzzy(Filter::Always, Moment::new(h1,m1,0), Moment::new(h2,m2,0)),
            &Event::Sunrise(m) =>
                DailyEvent::ByClosure(
                    Filter::Always,
                    Box::new(move|t| {
                        let daylight = calculate_daylight(at_utc(t), latitude, longitude);
                        let dusk = Duration::seconds((daylight.sunrise -
                                                      daylight.twilight_morning).num_seconds() / 2);
                        Moment::new_from_timespec(daylight.twilight_morning + dusk)
                    }), Duration::minutes(m as i64)),
            &Event::Sunset(m) =>
                DailyEvent::ByClosure(
                    Filter::Always,
                    Box::new(move|t| {
                        let daylight = calculate_daylight(at_utc(t), latitude, longitude);
                        let dusk = Duration::seconds((daylight.sunset -
                                                      daylight.twilight_evening).num_seconds() / 2);
                        Moment::new_from_timespec(daylight.sunset + dusk)
                    }), Duration::minutes(m as i64)),
        }
    }
}

#[derive(Debug)]
pub struct Toggle {
    pub alias: String,
    pub start: Event,
    pub end: Event
}

impl Toggle {
    fn new(alias: &str, table: &toml::Table) -> Result<Toggle> {
        let start = try!(table.iter().find(|&(k,_)| k.starts_with("start_")).map_or(
                Err(Error::MissingStartEvent(alias.into())),
                |(k,v)| Event::new(&k[..], v)));
        let end = try!(table.iter().find(|&(k,_)| k.starts_with("end_")).map_or(
                Err(Error::MissingEndEvent(alias.into())),
                |(k,v)| Event::new(&k[..], v)));
        Ok(Toggle {
            alias: alias.into(),
            start: start,
            end: end
        })
    }
}

#[derive(Debug)]
pub enum CircleSetting {
    Off,
    On,
    Schedule
}

impl CircleSetting {
    fn new(setting_as_str: &str) -> Option<CircleSetting> {
        match setting_as_str {
            "off" => Some(CircleSetting::Off),
            "on" => Some(CircleSetting::On),
            "schedule" => Some(CircleSetting::Schedule),
            _ => None
        }
    }
}

#[derive(Debug)]
pub struct Circle {
    pub alias: String,
    pub mac: u64,
    pub default: CircleSetting,
    pub toggles: Vec<Toggle>
}

impl Circle {
    fn new(alias: &str, table: &toml::Table) -> Result<Circle> {
        let mut mac = None;
        let mut default = None;
        let mut toggles = vec![];

        for (k, v) in table {
            match &k[..] {
                CIRCLE_MAC => {
                    mac = v.as_str().map_or(None, |s| u64::from_str_radix(s, 16).ok());
                },
                CIRCLE_DEFAULT => {
                    default = v.as_str().map_or(None, |s| CircleSetting::new(s));
                },
                _ => {
                    let toggle = try!(v.as_table().map_or(
                            Err(Error::ScheduleExpected(alias.into())),
                            |t| Toggle::new(&k[..], t)));
                    toggles.push(toggle);
                }
            }
        }

        Ok(Circle {
            alias: alias.into(),
            mac: try!(mac.ok_or(Error::InvalidMac(alias.into()))),
            default: try!(default.ok_or(Error::InvalidDefault(alias.into()))),
            toggles: toggles
        })
    }
}

#[derive(Debug)]
pub struct Device {
    pub serial_device: Option<String>,
    pub latitude: f64,
    pub longitude: f64,
    pub ntp_server: String,
}

impl Device {
    fn new(table: &toml::Table) -> Result<Device> {
        let mut serial_device = None;
        let mut latitude = None;
        let mut longitude = None;
        let mut ntp = None;

        for (k, v) in table {
            match &k[..] {
                CONFIG_DEVICE => {
                    if let Some(string) = v.as_str() {
                        serial_device = Some(string.into());
                    }
                },
                CONFIG_LATITUDE => {
                    if let Some(lat) = v.as_float() {
                        latitude = Some(lat);
                    }
                },
                CONFIG_LONGITUDE => {
                    if let Some(long) = v.as_float() {
                        longitude = Some(long);
                    }
                },
                CONFIG_NTP_SERVER => {
                    if let Some(string) = v.as_str() {
                        ntp = Some(string.into());
                    }
                },
                _ => {}
            }
        }

        latitude.map_or(Err(Error::LocationMissing), |lat|
             longitude.map_or(Err(Error::LocationMissing), |long|
             ntp.map_or(Err(Error::MissingNTP), |ntp:String|
             serial_device.map_or(
                    Ok(Device{serial_device: None, latitude:lat, longitude:long, ntp_server:ntp.clone()}),
                    |dev| Ok(Device{serial_device: Some(dev), latitude:lat, longitude: long, ntp_server:ntp.clone()})))))
    }
}

#[derive(Debug)]
pub struct Config {
    pub device: Device,
    pub circles: Vec<Circle>
}

impl Config {
    pub fn new(configfile: &path::PathBuf) -> Result<Config> {
        let mut circles = vec![];
        let mut device = None;

        let mut config = String::new();
        let mut file = try!(fs::File::open(configfile));
        try!(file.read_to_string(&mut config));
        let config = try!(toml::Parser::new(&config).parse().ok_or(Error::InvalidToml));

        for (k,v) in config {
            if let Some(table) = v.as_table() {
                match &k[..] {
                    CONFIG_HEAD => {
                        device = Some(try!(Device::new(table)));
                    },
                    _ => {
                        circles.push(try!(Circle::new(&k[..], table)));
                    }
                }
            }
        }

        Ok(Config {
            device: device.unwrap(),
            circles: circles
        })
    }
}
<commit_msg>config: replaced panic with proper error<commit_after>// This module loads the configuration file

use dailyschedule::{DailyEvent, Filter, Moment};
use std::convert::Into;
use std::error;
use std::fmt;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::path;
use std::result;
use time::{Duration, at_utc};
use toml;
use daylight::calculate_daylight;

const CONFIG_HEAD: &'static str = "config";
const CONFIG_DEVICE: &'static str = "device";
const CONFIG_LATITUDE: &'static str = "latitude";
const CONFIG_LONGITUDE: &'static str = "longitude";
const CONFIG_NTP_SERVER: &'static str = "ntp";
const CIRCLE_MAC: &'static str = "mac";
const CIRCLE_DEFAULT: &'static str = "default";

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    MissingEventSpecifier(String),
    WrongEventSpecifier(String),
    MissingStartEvent(String),
    MissingEndEvent(String),
    ScheduleExpected(String),
    InvalidMac(String),
    InvalidDefault(String),
    MissingConfig,
    MissingNTP,
    LocationMissing,
    InvalidToml,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref err) => fmt::Display::fmt(err, f),
            _ => write!(f, "Keeper configuraton error"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => error::Error::description(err),
            _ => "Keeper configuration error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref err) => err.cause(),
            _ => None,
        }
    }
}

#[derive(Debug)]
pub enum Event {
    Fixed(u8, u8),
    Fuzzy((u8, u8), (u8, u8)),
    Sunrise(u16),
    Sunset(u16)
}

impl Event {
    fn time_in_a_day(value: &toml::Value) -> Option<(u8, u8)> {
        let mapped: Option<Vec<i64>> = value.as_slice()
                                            .map(|arr| arr.iter()
                                                          .filter_map(|x|x.as_integer())
                                                          .collect());
        mapped.map_or(None, |v| {
            match v.len() {
                2 => {
                    let (h,m) = (v[0], v[1]);
                    if h < 0 || h >= 48 {
                        None
                    } else if m < 0 || m >= 60 {
                        None
                    } else {
                        Some((h as u8, m as u8))
                    }
                },
                _ => None
            }
        })
    }

    fn new(key: &str, value: &toml::Value) -> Result<Event> {
        let specifier = try!(key.split("_").last().ok_or(
                Error::MissingEventSpecifier(key.into())));

        match specifier {
            "fixed" => Event::time_in_a_day(value).map(|(f,s)| Event::Fixed(f,s)).ok_or(
                Error::WrongEventSpecifier("fixed must hold a array of two integers".into())),
            "fuzzy" => value.as_slice().map_or(None, |s| {
                    match s.len() {
                        2 => {
                            let first = Event::time_in_a_day(&s[0]);
                            let second = Event::time_in_a_day(&s[1]);
                            first.map_or(None, |f| second.map(|s| Event::Fuzzy(f,s)))
                        },
                        _ => None
                    }
                }).ok_or(Error::WrongEventSpecifier("fuzzy must hold a array of two arrays of two integers".into())),
            "sunrise" => value.as_integer().map(|i| Event::Sunrise(i as u16)).ok_or(
                Error::WrongEventSpecifier("sunrise must only hold one integer (variance in minutes)".into())),
            "sunset" => value.as_integer().map(|i| Event::Sunset(i as u16)).ok_or(
                Error::WrongEventSpecifier("sunset must only hold one integer (variance in minutes)".into())),
            _ => Err(Error::WrongEventSpecifier("unsupported specifier".into()))
        }
    }

    pub fn into_dailyevent(&self, device: &Device) -> DailyEvent {
        let latitude = device.latitude;
        let longitude = device.longitude;
        match self {
            &Event::Fixed(h,m) => DailyEvent::Fixed(Filter::Always, Moment::new(h,m,0)),
            &Event::Fuzzy((h1,m1),(h2,m2)) =>
                DailyEvent::Fuzzy(Filter::Always, Moment::new(h1,m1,0), Moment::new(h2,m2,0)),
            &Event::Sunrise(m) =>
                DailyEvent::ByClosure(
                    Filter::Always,
                    Box::new(move|t| {
                        let daylight = calculate_daylight(at_utc(t), latitude, longitude);
                        let dusk = Duration::seconds((daylight.sunrise -
                                                      daylight.twilight_morning).num_seconds() / 2);
                        Moment::new_from_timespec(daylight.twilight_morning + dusk)
                    }), Duration::minutes(m as i64)),
            &Event::Sunset(m) =>
                DailyEvent::ByClosure(
                    Filter::Always,
                    Box::new(move|t| {
                        let daylight = calculate_daylight(at_utc(t), latitude, longitude);
                        let dusk = Duration::seconds((daylight.sunset -
                                                      daylight.twilight_evening).num_seconds() / 2);
                        Moment::new_from_timespec(daylight.sunset + dusk)
                    }), Duration::minutes(m as i64)),
        }
    }
}

#[derive(Debug)]
pub struct Toggle {
    pub alias: String,
    pub start: Event,
    pub end: Event
}

impl Toggle {
    fn new(alias: &str, table: &toml::Table) -> Result<Toggle> {
        let start = try!(table.iter().find(|&(k,_)| k.starts_with("start_")).map_or(
                Err(Error::MissingStartEvent(alias.into())),
                |(k,v)| Event::new(&k[..], v)));
        let end = try!(table.iter().find(|&(k,_)| k.starts_with("end_")).map_or(
                Err(Error::MissingEndEvent(alias.into())),
                |(k,v)| Event::new(&k[..], v)));
        Ok(Toggle {
            alias: alias.into(),
            start: start,
            end: end
        })
    }
}

#[derive(Debug)]
pub enum CircleSetting {
    Off,
    On,
    Schedule
}

impl CircleSetting {
    fn new(setting_as_str: &str) -> Option<CircleSetting> {
        match setting_as_str {
            "off" => Some(CircleSetting::Off),
            "on" => Some(CircleSetting::On),
            "schedule" => Some(CircleSetting::Schedule),
            _ => None
        }
    }
}

#[derive(Debug)]
pub struct Circle {
    pub alias: String,
    pub mac: u64,
    pub default: CircleSetting,
    pub toggles: Vec<Toggle>
}

impl Circle {
    fn new(alias: &str, table: &toml::Table) -> Result<Circle> {
        let mut mac = None;
        let mut default = None;
        let mut toggles = vec![];

        for (k, v) in table {
            match &k[..] {
                CIRCLE_MAC => {
                    mac = v.as_str().map_or(None, |s| u64::from_str_radix(s, 16).ok());
                },
                CIRCLE_DEFAULT => {
                    default = v.as_str().map_or(None, |s| CircleSetting::new(s));
                },
                _ => {
                    let toggle = try!(v.as_table().map_or(
                            Err(Error::ScheduleExpected(alias.into())),
                            |t| Toggle::new(&k[..], t)));
                    toggles.push(toggle);
                }
            }
        }

        Ok(Circle {
            alias: alias.into(),
            mac: try!(mac.ok_or(Error::InvalidMac(alias.into()))),
            default: try!(default.ok_or(Error::InvalidDefault(alias.into()))),
            toggles: toggles
        })
    }
}

#[derive(Debug)]
pub struct Device {
    pub serial_device: Option<String>,
    pub latitude: f64,
    pub longitude: f64,
    pub ntp_server: String,
}

impl Device {
    fn new(table: &toml::Table) -> Result<Device> {
        let mut serial_device = None;
        let mut latitude = None;
        let mut longitude = None;
        let mut ntp = None;

        for (k, v) in table {
            match &k[..] {
                CONFIG_DEVICE => {
                    if let Some(string) = v.as_str() {
                        serial_device = Some(string.into());
                    }
                },
                CONFIG_LATITUDE => {
                    if let Some(lat) = v.as_float() {
                        latitude = Some(lat);
                    }
                },
                CONFIG_LONGITUDE => {
                    if let Some(long) = v.as_float() {
                        longitude = Some(long);
                    }
                },
                CONFIG_NTP_SERVER => {
                    if let Some(string) = v.as_str() {
                        ntp = Some(string.into());
                    }
                },
                _ => {}
            }
        }

        latitude.map_or(Err(Error::LocationMissing), |lat|
             longitude.map_or(Err(Error::LocationMissing), |long|
             ntp.map_or(Err(Error::MissingNTP), |ntp:String|
             serial_device.map_or(
                    Ok(Device{serial_device: None, latitude:lat, longitude:long, ntp_server:ntp.clone()}),
                    |dev| Ok(Device{serial_device: Some(dev), latitude:lat, longitude: long, ntp_server:ntp.clone()})))))
    }
}

#[derive(Debug)]
pub struct Config {
    pub device: Device,
    pub circles: Vec<Circle>
}

impl Config {
    pub fn new(configfile: &path::PathBuf) -> Result<Config> {
        let mut circles = vec![];
        let mut device = None;

        let mut config = String::new();
        let mut file = try!(fs::File::open(configfile));
        try!(file.read_to_string(&mut config));
        let config = try!(toml::Parser::new(&config).parse().ok_or(Error::InvalidToml));

        for (k,v) in config {
            if let Some(table) = v.as_table() {
                match &k[..] {
                    CONFIG_HEAD => {
                        device = Some(try!(Device::new(table)));
                    },
                    _ => {
                        circles.push(try!(Circle::new(&k[..], table)));
                    }
                }
            }
        }

        Ok(Config {
            device: try!(device.ok_or(Error::MissingConfig)),
            circles: circles
        })
    }
}
<|endoftext|>