<commit_before>#[macro_use]
extern crate log;
extern crate serde;
extern crate serde_json;

use serde::{Serialize, Serializer};
use serde_json::to_string;
use std::io::{Write, stderr, stdout};

#[macro_export]
macro_rules! json_object {
    ( $( $key:expr => $value:expr ),* ) => {
        {
            use serde_json::{Value, to_value, Map};
            let mut m: Map<String, Value> = Map::new();
            $(
                m.insert($key.to_owned(), to_value(&$value));
            )*
            m
        }
    }
}

#[derive(Debug)]
pub struct SLogMetadata<'a> {
    pub target: &'a str,
    pub level: log::LogLevel,
}

#[derive(Debug)]
pub struct SLogLocation<'a> {
    pub module_path: &'a str,
    pub file: &'a str,
    pub line: u32,
}

#[derive(Debug)]
pub struct SLogInfo<'a> {
    pub metadata: SLogMetadata<'a>,
    pub location: SLogLocation<'a>,
}

impl<'a> SLogInfo<'a> {
    pub fn metadata(&self) -> &SLogMetadata {
        &self.metadata
    }

    pub fn location(&self) -> &SLogLocation {
        &self.location
    }
}

pub trait StructuredLog {
    fn slog(&self, info: &SLogInfo) -> String;
}

#[inline]
pub fn serialize<T>(value: &T, info: &SLogInfo) -> String
    where T: StructuredLog
{
    value.slog(info)
}

#[macro_export]
macro_rules! serialize {
    (target: $target:expr, level: $level:expr, $value:expr) => {
        {
            $crate::serialize(&$value, &$crate::SLogInfo {
                metadata: $crate::SLogMetadata {
                    target: $target,
                    level: $level
                },
                location: $crate::SLogLocation {
                    module_path: module_path!(),
                    file: file!(),
                    line: line!()
                }
            })
        }
    }
}

#[derive(Debug)]
pub struct SLogJson<'a, T: 'a>(&'a T);

impl<'a, T: Serialize> SLogJson<'a, T> {
    pub fn new<'b>(value: &'b T) -> SLogJson<'b, T> {
        SLogJson(value)
    }
}

impl<'a, T: Serialize> Serialize for SLogJson<'a, T> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        self.0.serialize(serializer)
    }
}

impl<'a, T: Serialize> StructuredLog for SLogJson<'a, T> {
    fn slog(&self, info: &SLogInfo) -> String {
        let obj = json_object! {
            "target" => info.metadata.target,
            "level" => info.metadata.level.to_string(),
            "location" => json_object! {
                "module_path" => info.location.module_path,
                "file" => info.location.file,
                "line" => info.location.line
            },
            "value" => self
        };
        to_string(&obj).unwrap_or_else(|err| {
            writeln!(stderr(), "{}, {:?}", err, obj).unwrap();

            let msg = "Serializing error occured in s_structured_log in serde::to_string. \
                       Details was written out to STDERR.";
            format!("{{ \"level\": \"{}\", \"value\": \"{}\" }}",
                    log::LogLevel::Error,
                    msg)
        })
    }
}

#[macro_export]
macro_rules! s_error {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Error, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_error!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

#[macro_export]
macro_rules! s_warn {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Warn, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_warn!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

#[macro_export]
macro_rules! s_info {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Info, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_info!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

#[macro_export]
macro_rules! s_debug {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Debug, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_debug!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

#[macro_export]
macro_rules! s_trace {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Trace, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_trace!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

fn escape_str(x: &str) -> String {
    let mut v = Vec::new();
    let mut l = 0;
    let bytes = x.as_bytes();
    for (i, b) in bytes.iter().enumerate() {
        let escaped = match *b {
            b'\x00' => r"\u0000",
            b'\x01' => r"\u0001",
            b'\x02' => r"\u0002",
            b'\x03' => r"\u0003",
            b'\x04' => r"\u0004",
            b'\x05' => r"\u0005",
            b'\x06' => r"\u0006",
            b'\x07' => r"\u0007",
            b'\x08' => r"\b",
            b'\x09' => r"\t",
            b'\x10' => r"\n",
            b'\x11' => r"\u0011",
            b'\x12' => r"\f",
            b'\x13' => r"\r",
            b'\x14' => r"\u0014",
            b'\x15' => r"\u0015",
            b'\x16' => r"\u0016",
            b'\x17' => r"\u0017",
            b'\x18' => r"\u0018",
            b'\x19' => r"\u0019",
            b'\\' => r"\\",
            b'"' => r#"\""#,
            _ => {
                continue;
            }
        };

        if l < i {
            v.extend_from_slice(&bytes[l..i]);
        }

        v.extend_from_slice(escaped.as_bytes());

        l = i + 1;
    }

    String::from_utf8(v).unwrap()
}

pub enum LoggerOutput {
    Stdout,
    Stderr,
}

struct JsonLogger {
    filter: log::LogLevelFilter,
    output: LoggerOutput,
}

impl log::Log for JsonLogger {
    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= self.filter
    }

    fn log(&self, record: &log::LogRecord) {
        if !self.enabled(record.metadata()) {
            return;
        }

        let location = format!(r#"{{"module_path":"{}","file":"{}","line":{}}}"#,
                               record.location().module_path(),
                               record.location().file(),
                               record.location().line());

        let meta = format!(r#"{{"target":"{}","location":{}}}"#,
                           record.target(),
                           location);

        let value = if record.target().starts_with("json:") {
            format!("{}", record.args())
        } else {
            format!(r#""{}""#, escape_str(&record.args().to_string()))
        };

        let json = format!(r#"{{"level":"{}","meta":{},"value":{}}}"#,
                           record.level().to_string(),
                           meta,
                           value);

        let _ = match self.output {
            LoggerOutput::Stderr => writeln!(stderr(), "{}", json),
            LoggerOutput::Stdout => writeln!(stdout(), "{}", json),
        };
    }
}

pub fn init(output: LoggerOutput, log_level: log::LogLevelFilter) {
    let logger = JsonLogger {
        filter: log_level,
        output: output,
    };

    log::set_logger(|max_log_level| {
            max_log_level.set(logger.filter);
            Box::new(logger)
        })
        .unwrap();
}

#[cfg(feature = "documentation")]
pub mod doc;

#[cfg(test)]
mod tests {
    #[test]
    fn simple_logger() {}

    #[test]
    fn escape_str() {
        let x = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\\\"";
        let expected = r#"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u0011\f\r\u0014\u0015\u0016\u0017\u0018\u0019\\\""#.to_owned();
        assert_eq!(::escape_str(x), expected);
    }
}
<commit_msg>Add json_format! and improve making json string<commit_after>#[macro_use]
extern crate log;
extern crate serde;
extern crate serde_json;

use serde::{Serialize, Serializer};
use serde_json::to_string;
use std::io::{Write, stderr, stdout};

#[macro_export]
macro_rules! json_object {
    ( $( $key:expr => $value:expr ),* ) => {
        {
            use serde_json::{Value, to_value, Map};
            let mut m: Map<String, Value> = Map::new();
            $(
                m.insert($key.to_owned(), to_value(&$value));
            )*
            m
        }
    }
}

#[macro_export]
macro_rules! json_format {
    ( $( $key:expr => $value:expr ),* ) => {
        {
            let mut s = String::with_capacity(128);
            s.push('{');
            $(
                s.push_str(&format!(r#""{}":{},"#, $key, $value));
            )*
            let _ = s.pop();
            s.push('}');
            s
        }
    };
    ( $( $value:expr ),* ) => {
        {
            let mut s = String::with_capacity(128);
            s.push('[');
            $(
                s.push_str(&format!("{},", $value));
            )*
            let _ = s.pop();
            s.push(']');
            s
        }
    }
}

#[macro_export]
macro_rules! q {
    ( $value:expr ) => {
        format!("\"{}\"", $value)
    }
}

#[derive(Debug)]
pub struct SLogMetadata<'a> {
    pub target: &'a str,
    pub level: log::LogLevel,
}

#[derive(Debug)]
pub struct SLogLocation<'a> {
    pub module_path: &'a str,
    pub file: &'a str,
    pub line: u32,
}

#[derive(Debug)]
pub struct SLogInfo<'a> {
    pub metadata: SLogMetadata<'a>,
    pub location: SLogLocation<'a>,
}

impl<'a> SLogInfo<'a> {
    pub fn metadata(&self) -> &SLogMetadata {
        &self.metadata
    }

    pub fn location(&self) -> &SLogLocation {
        &self.location
    }
}

pub trait StructuredLog {
    fn slog(&self, info: &SLogInfo) -> String;
}

#[inline]
pub fn serialize<T>(value: &T, info: &SLogInfo) -> String
    where T: StructuredLog
{
    value.slog(info)
}

#[macro_export]
macro_rules! serialize {
    (target: $target:expr, level: $level:expr, $value:expr) => {
        {
            $crate::serialize(&$value, &$crate::SLogInfo {
                metadata: $crate::SLogMetadata {
                    target: $target,
                    level: $level
                },
                location: $crate::SLogLocation {
                    module_path: module_path!(),
                    file: file!(),
                    line: line!()
                }
            })
        }
    }
}

#[derive(Debug)]
pub struct SLogJson<'a, T: 'a>(&'a T);

impl<'a, T: Serialize> SLogJson<'a, T> {
    pub fn new<'b>(value: &'b T) -> SLogJson<'b, T> {
        SLogJson(value)
    }
}

impl<'a, T: Serialize> Serialize for SLogJson<'a, T> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        self.0.serialize(serializer)
    }
}

impl<'a, T: Serialize> StructuredLog for SLogJson<'a, T> {
    fn slog(&self, info: &SLogInfo) -> String {
        let obj = json_object! {
            "target" => info.metadata.target,
            "level" => info.metadata.level.to_string(),
            "location" => json_object! {
                "module_path" => info.location.module_path,
                "file" => info.location.file,
                "line" => info.location.line
            },
            "value" => self
        };
        to_string(&obj).unwrap_or_else(|err| {
            writeln!(stderr(), "{}, {:?}", err, obj).unwrap();

            let msg = "Serializing error occured in s_structured_log in serde::to_string. \
                       Details was written out to STDERR.";
            json_format! {
                "level" => q!(log::LogLevel::Error),
                "value" => q!(msg)
            }
        })
    }
}

#[macro_export]
macro_rules! s_error {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Error, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_error!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

#[macro_export]
macro_rules! s_warn {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Warn, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_warn!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

#[macro_export]
macro_rules! s_info {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Info, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_info!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

#[macro_export]
macro_rules! s_debug {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Debug, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_debug!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

#[macro_export]
macro_rules! s_trace {
    (target: $target:expr, $value:expr) => {
        {
            use log;
            trace!(target: $target, "{}", serialize!(target: $target, level: log::LogLevel::Trace, $crate::SLogJson::new(&$value)));
        }
    };
    ($value:expr) => {
        {
            s_trace!(target: &format!("json:{}", module_path!()), $value);
        }
    };
}

fn escape_str(x: &str) -> String {
    let mut v = Vec::new();
    let mut l = 0;
    let bytes = x.as_bytes();
    for (i, b) in bytes.iter().enumerate() {
        let escaped = match *b {
            b'\x00' => r"\u0000",
            b'\x01' => r"\u0001",
            b'\x02' => r"\u0002",
            b'\x03' => r"\u0003",
            b'\x04' => r"\u0004",
            b'\x05' => r"\u0005",
            b'\x06' => r"\u0006",
            b'\x07' => r"\u0007",
            b'\x08' => r"\b",
            b'\x09' => r"\t",
            b'\x10' => r"\n",
            b'\x11' => r"\u0011",
            b'\x12' => r"\f",
            b'\x13' => r"\r",
            b'\x14' => r"\u0014",
            b'\x15' => r"\u0015",
            b'\x16' => r"\u0016",
            b'\x17' => r"\u0017",
            b'\x18' => r"\u0018",
            b'\x19' => r"\u0019",
            b'\\' => r"\\",
            b'"' => r#"\""#,
            _ => {
                continue;
            }
        };

        if l < i {
            v.extend_from_slice(&bytes[l..i]);
        }

        v.extend_from_slice(escaped.as_bytes());

        l = i + 1;
    }

    String::from_utf8(v).unwrap()
}

pub enum LoggerOutput {
    Stdout,
    Stderr,
}

struct JsonLogger {
    filter: log::LogLevelFilter,
    output: LoggerOutput,
}

impl log::Log for JsonLogger {
    fn enabled(&self, metadata: &log::LogMetadata) -> bool {
        metadata.level() <= self.filter
    }

    fn log(&self, record: &log::LogRecord) {
        if !self.enabled(record.metadata()) {
            return;
        }

        let json = json_format! {
            "level" => q!(record.level()),
            "meta" => json_format! {
                "target" => q!(record.target()),
                "location" => json_format! {
                    "module_path" => q!(record.location().module_path()),
                    "file" => q!(record.location().file()),
                    "line" => record.location().line()
                }
            },
            "value" => if record.target().starts_with("json:") {
                format!("{}", record.args())
            } else {
                q!(escape_str(&record.args().to_string()))
            }
        };

        let _ = match self.output {
            LoggerOutput::Stderr => writeln!(stderr(), "{}", json),
            LoggerOutput::Stdout => writeln!(stdout(), "{}", json),
        };
    }
}

pub fn init(output: LoggerOutput, log_level: log::LogLevelFilter) {
    let logger = JsonLogger {
        filter: log_level,
        output: output,
    };

    log::set_logger(|max_log_level| {
            max_log_level.set(logger.filter);
            Box::new(logger)
        })
        .unwrap();
}

#[cfg(feature = "documentation")]
pub mod doc;

#[cfg(test)]
mod tests {
    #[test]
    fn simple_logger() {}

    #[test]
    fn escape_str() {
        let x = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\\\"";
        let expected = r#"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u0011\f\r\u0014\u0015\u0016\u0017\u0018\u0019\\\""#.to_owned();
        assert_eq!(::escape_str(x), expected);
    }

    #[test]
    fn json_format() {
        let obj = json_format! {
            "key1" => q!("value1"),
            "key2" => 1
        };

        let array = json_format![q!("value1"), 1];

        assert_eq!(obj, r#"{"key1":"value1","key2":1}"#);
        assert_eq!(array, r#"["value1",1]"#);
    }
}
<|endoftext|>


<commit_before>#![feature(io, core)]
//! Fern is a runtime-configurable rust logging library.

//! Current features are:
//!
//! - Multiple loggers. You can create as many loggers as you need, and configure them separately.
//! - Configurable output format via closures.
//! - Multiple outputs per logger - current options are to a file, or to stdout/stderr (or any
//!   combination of those)
//! - Each output can have a Level configured, so you can output all log messages to a log file,
//!   and only have warnings and above show up in the console!
//! - You can also define your own custom logging endpoints - have messages end up where you need
//!   them!
//! - Thread-local logger storage. This allows for convenient debug/info/warning/severe!() and
//!   log!() macros via the fern_macros package.
//!
//! fern is still in development, and most features are experimental. The library is subject to
//! change in non-backwards-compatible ways.
//!
//! This library can only be used while complying to the license terms in the `LICENSE` file.
//!
//! Examples
//! ========
//!
//! Usually, the first thing you want to do is create a logger. In fern, you can do this by first
//! creating a LoggerConfig struct, and then calling `.into_logger()` to turn it into a logger.
//!
//! Here's a logger that simply logs all messages to stdout, and an output.log file, formatting
//! each message with the current date, time, and logging level.
//!
//! ```no_test
//! let logger_config = fern::LoggerConfig {
//!     format: box |msg: &str, level: &fern::Level| {
//!         return format!("[{}][{}] {}", chrono::Local::now().format("%Y-%m-%d][%H:%M:%S"), level, msg);
//!     },
//!     output: vec![fern::OutputConfig::Stdout, fern::OutputConfig::File(Path::new("output.log"))],
//!     level: fern::Level::Debug,
//! };
//! ```
//!
//! In the above example, here's what each part does.
//!
//! `format:` is a closure which all messages will be run through. In this example, use a
//! format!() macro to format the messages using the current time, date, and logging level.
//!
//! Side note: `chrono::Local::now().format("%Y-%m-%d][%H:%M:%S")` is a usage of the chrono time
//! library, and just returns the date in the format described. An output of this might look like
//! `2014-12-01][12:55:04`.
//!
//! With this formatting, the final output of the logger will look something like:
//!
//! ```text
//! [2014-12-01][12:55:04][INFO] A message logged at the Level::Info logging level.
//! ```
//!
//! `output:` is a Vec<> of other configurations to send the messages to. In this example, we send
//! them to `OutputConfig::Stdout` and `OutputConfig::File(Path::new("output.log"))`.
//! This will send messages to the console, and to a file called "output.log".
//!
//! `level:` is a `fern::Level` which describes the minimum level that should be allowed to pass
//! through this logger. Setting this to `Level::Debug` allows all messages to be logged, as Debug
//! is the lowest logging level.
//!
//! After creating your logging config, you can turn it into a Logger using `into_logger()`:
//!
//! ```no_test
//! let logger = match logger_config.into_logger() {
//!     Some(v) => v,
//!     Err(e) => panic!("Failed to create logger! Error: {}", e),
//! };
//! ```
//!
//! Eventually, this section will contain a few more examples as well. For now though, the above,
//! along with the LoggerConfig and OutputConfig docs, should be enough to get you started on
//! configuring your logger.
//!
//! #### Logging
//!
//! The next part of logging that you'll probably want to do is actually output some messages.
//!
//! The recommended/easiest way to do this is using the `local` module, along with the
//! `fern_macros` crate.
//!
//! To initialize your logger into thread-local storage for use, you can use
//! `fern::local::set_thread_logger()`
//!
//! ```no_test
//! use std::sync;
//!
//! fern::local::set_thread_logger(sync::Arc::new(logger));
//! ```
//!
//! You can then log anywhere in this thread using the following macros from fern_macros:
//!
//! ```no_test
//! #[macro_use]
//! extern crate fern_macros;
//!
//! // ...
//!
//! info!("A message logged at info level");
//!
//! let var = true;
//! debug!("Debugging message containing a variable value: {}", var);
//!
//! warning!("Something bad happened!");
//!
//! severe!("Something really bad happened!");
//! ```
//!
//! If your application is multi-threaded, you can spread the logger across threads as follows:
//!
//! ```no_test
//! use std::sync;
//!
//! let logger_arc = sync::Arc::new(logger); // Create a reference counted logger
//!
//! fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this thread.
//!
//! spawn(move || {
//!     // Initialize the logger for this worker thread.
//!     fern::local::set_thread_logger(logger_arc.clone());
//!
//!     // Do other calculations, and log more here as well.
//! });
//! ```
//!
//! You can also pass the reference counted logger between functions - if you don't want to
//! type out `sync::Arc<Box<fern::Logger + Sync + Send>>` for all the function declarations, you
//! can use `fern::ArcLogger` instead.

pub use errors::Error;
pub use api::{Logger, BoxedLogger, ArcLogger, Level};
pub use config::{LoggerConfig, OutputConfig};
pub use loggers::NullLogger;

#[unstable]
pub mod local;
mod api;
mod config;
mod loggers;
mod errors;
<commit_msg>Fixed typo in documentation: Some(v) -> Ok(v)<commit_after>#![feature(io, core)]
//! Fern is a runtime-configurable rust logging library.

//! Current features are:
//!
//! - Multiple loggers. You can create as many loggers as you need, and configure them separately.
//! - Configurable output format via closures.
//! - Multiple outputs per logger - current options are to a file, or to stdout/stderr (or any
//!   combination of those)
//! - Each output can have a Level configured, so you can output all log messages to a log file,
//!   and only have warnings and above show up in the console!
//! - You can also define your own custom logging endpoints - have messages end up where you need
//!   them!
//! - Thread-local logger storage. This allows for convenient debug/info/warning/severe!() and
//!   log!() macros via the fern_macros package.
//!
//! fern is still in development, and most features are experimental. The library is subject to
//! change in non-backwards-compatible ways.
//!
//! This library can only be used while complying to the license terms in the `LICENSE` file.
//!
//! Examples
//! ========
//!
//! Usually, the first thing you want to do is create a logger. In fern, you can do this by first
//! creating a LoggerConfig struct, and then calling `.into_logger()` to turn it into a logger.
//!
//! Here's a logger that simply logs all messages to stdout, and an output.log file, formatting
//! each message with the current date, time, and logging level.
//!
//! ```no_test
//! let logger_config = fern::LoggerConfig {
//!     format: box |msg: &str, level: &fern::Level| {
//!         return format!("[{}][{}] {}", chrono::Local::now().format("%Y-%m-%d][%H:%M:%S"), level, msg);
//!     },
//!     output: vec![fern::OutputConfig::Stdout, fern::OutputConfig::File(Path::new("output.log"))],
//!     level: fern::Level::Debug,
//! };
//! ```
//!
//! In the above example, here's what each part does.
//!
//! `format:` is a closure which all messages will be run through. In this example, use a
//! format!() macro to format the messages using the current time, date, and logging level.
//!
//! Side note: `chrono::Local::now().format("%Y-%m-%d][%H:%M:%S")` is a usage of the chrono time
//! library, and just returns the date in the format described. An output of this might look like
//! `2014-12-01][12:55:04`.
//!
//! With this formatting, the final output of the logger will look something like:
//!
//! ```text
//! [2014-12-01][12:55:04][INFO] A message logged at the Level::Info logging level.
//! ```
//!
//! `output:` is a Vec<> of other configurations to send the messages to. In this example, we send
//! them to `OutputConfig::Stdout` and `OutputConfig::File(Path::new("output.log"))`.
//! This will send messages to the console, and to a file called "output.log".
//!
//! `level:` is a `fern::Level` which describes the minimum level that should be allowed to pass
//! through this logger. Setting this to `Level::Debug` allows all messages to be logged, as Debug
//! is the lowest logging level.
//!
//! After creating your logging config, you can turn it into a Logger using `into_logger()`:
//!
//! ```no_test
//! let logger = match logger_config.into_logger() {
//!     Ok(v) => v,
//!     Err(e) => panic!("Failed to create logger! Error: {}", e),
//! };
//! ```
//!
//! Eventually, this section will contain a few more examples as well. For now though, the above,
//! along with the LoggerConfig and OutputConfig docs, should be enough to get you started on
//! configuring your logger.
//!
//! #### Logging
//!
//! The next part of logging that you'll probably want to do is actually output some messages.
//!
//! The recommended/easiest way to do this is using the `local` module, along with the
//! `fern_macros` crate.
//!
//! To initialize your logger into thread-local storage for use, you can use
//! `fern::local::set_thread_logger()`
//!
//! ```no_test
//! use std::sync;
//!
//! fern::local::set_thread_logger(sync::Arc::new(logger));
//! ```
//!
//! You can then log anywhere in this thread using the following macros from fern_macros:
//!
//! ```no_test
//! #[macro_use]
//! extern crate fern_macros;
//!
//! // ...
//!
//! info!("A message logged at info level");
//!
//! let var = true;
//! debug!("Debugging message containing a variable value: {}", var);
//!
//! warning!("Something bad happened!");
//!
//! severe!("Something really bad happened!");
//! ```
//!
//! If your application is multi-threaded, you can spread the logger across threads as follows:
//!
//! ```no_test
//! use std::sync;
//!
//! let logger_arc = sync::Arc::new(logger); // Create a reference counted logger
//!
//! fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this thread.
//!
//! spawn(move || {
//!     // Initialize the logger for this worker thread.
//!     fern::local::set_thread_logger(logger_arc.clone());
//!
//!     // Do other calculations, and log more here as well.
//! });
//! ```
//!
//! You can also pass the reference counted logger between functions - if you don't want to
//! type out `sync::Arc<Box<fern::Logger + Sync + Send>>` for all the function declarations, you
//! can use `fern::ArcLogger` instead.

pub use errors::Error;
pub use api::{Logger, BoxedLogger, ArcLogger, Level};
pub use config::{LoggerConfig, OutputConfig};
pub use loggers::NullLogger;

#[unstable]
pub mod local;
mod api;
mod config;
mod loggers;
mod errors;
<|endoftext|>


<commit_before>#![crate_id = "typedopts"]
#![crate_type = "lib"]

extern crate getopts;
extern crate serialize;
use getopts::Matches;
use std::from_str::FromStr;
use std::str::StrSlice;
use serialize::Decodable;

#[deriving(PartialEq, Eq, Show)]
pub enum ErrorType {
  UnimplementedDecoder,
  MissingField(String),
  ExpectedType(String, String, String),
  GenericError(String)
}

#[deriving(PartialEq, Eq, Show)]
pub struct Error {
  e: ErrorType
}

pub type DecodeResult<T> =  Result<T, ErrorType>;

pub struct Decoder {
  matches: Matches,
  cur: String,
  current_type: String
}

impl Decoder {
  pub fn new(matches: Matches) -> Decoder {
    Decoder {
      matches: matches,
      cur: "".to_string(),
      current_type: "".to_string()
    }
  }

  fn expected(&self, expected_type: String) -> ErrorType {
    ExpectedType(self.cur.to_string(),
                       expected_type.to_string(),
                       self.matches.opt_str(self.cur.as_slice()).unwrap())
  }

}

pub fn decode<T:Send+Decodable<Decoder, ErrorType>>(matches: Matches) -> DecodeResult<T> {
  let mut decoder = Decoder::new(matches);
  Decodable::decode(&mut decoder)
}

impl ErrorType {
  pub fn to_err_msg(self) -> String {
    match self {
      UnimplementedDecoder => format!("this function is not implemented"),
      MissingField(ref s)  => format!("the required field '{}' is not present", s),
      ExpectedType(ref field, ref expected, ref value) => {
        format!("Expected type '{}' for field '{}' but got value '{}'", expected, field, value)
      },
      GenericError(ref s)  => format!("generic error: {}", s)
    }
  }
}
impl<T:FromStr> Decoder {
  fn get_field<T:FromStr>(&self, field: &str) -> Option<T> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => None,
      Some(s) => FromStr::from_str(s.as_slice())
    }
  }
}

impl serialize::Decoder<ErrorType> for Decoder {

  fn read_nil(&mut self) -> DecodeResult<()> {
    Err(UnimplementedDecoder)
  }

  fn read_u64(&mut self)  -> DecodeResult<u64>  {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s.as_slice()) {
        None     => Err(self.expected("u64".to_string())),
        Some(nb) => Ok(nb)
      }
    }
  }
  fn read_u32(&mut self)  -> DecodeResult<u32>  { Ok(try!(self.read_u64()) as u32) }
  fn read_u16(&mut self)  -> DecodeResult<u16>  { Ok(try!(self.read_u64()) as u16) }
  fn read_u8 (&mut self)  -> DecodeResult<u8>   { Ok(try!(self.read_u64()) as u8) }
  fn read_uint(&mut self) -> DecodeResult<uint> { Ok(try!(self.read_u64()) as uint) }

  fn read_i64(&mut self) -> DecodeResult<i64> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s.as_slice()) {
        None     => Err(self.expected("i64".to_string())),
        Some(nb) => Ok(nb)
      }
    }
  }
  fn read_i32(&mut self) -> DecodeResult<i32> { Ok(try!(self.read_i64()) as i32) }
  fn read_i16(&mut self) -> DecodeResult<i16> { Ok(try!(self.read_i64()) as i16) }
  fn read_i8 (&mut self) -> DecodeResult<i8>  { Ok(try!(self.read_i64()) as i8) }
  fn read_int(&mut self) -> DecodeResult<int> { Ok(try!(self.read_i64()) as int) }

  fn read_f32(&mut self) -> DecodeResult<f32> { Ok(try!(self.read_f64()) as f32) }
  fn read_f64(&mut self) -> DecodeResult<f64> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s.as_slice()) {
        None     => Err(self.expected("f64".to_string())),
        Some(nb) => Ok(nb)
      }
    }
  }

  fn read_bool(&mut self) -> DecodeResult<bool> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s.as_slice()) {
        None     => Err(self.expected("boolean".to_string())),
        Some(b) => Ok(b)
      }
    }
  }

  fn read_char(&mut self) -> DecodeResult<char> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => if s.as_slice().char_len() == 1 { Ok(s.as_slice().char_at(0)) } else { Err(self.expected("char".to_string())) }
    }
  }

  fn read_str(&mut self) -> DecodeResult<String> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => Ok(s)
    }
  }

  fn read_enum<T>(&mut self, name: &str, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum: {}", name);
    self.current_type = name.to_string();
    f(self)
  }

  fn read_enum_variant<T>(&mut self, names: &[&str], f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum variant({}): {}", self.cur, names);
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(MissingField(self.cur.clone())),
      Some(s) => match names.iter().position(|&e| e == s.as_slice()) {
        None    => {
          let mut s = self.current_type.clone();
          s.push_str(" enum");
          Err(self.expected(s))
        },
        Some(i) => f(self, i)
      }
    }
  }

  fn read_enum_variant_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum variant_arg: {}", a_idx);
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_enum_struct_variant<T>(&mut self, names: &[&str], f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum struct variant: {}", names);
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_enum_struct_variant_field<T>(&mut self, f_name: &str, f_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum struct variant field: {}, {}", f_name, f_idx);
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_struct<T>(&mut self, s_name: &str, len: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading struct: {} | len = {}", s_name, len);
    self.cur = s_name.to_string();
    f(self)
  }

  fn read_struct_field<T>(&mut self, f_name: &str, f_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading struct field: {} | idx = {}", f_name, f_idx);
    self.cur = f_name.to_string();
    let data = f(self);
    //println!("got struct field data: {}", data);
    data
  }

  fn read_option<T>(&mut self, f: |&mut Decoder, bool| -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("read_option");
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => {
        //println!("option not there");
        f(self, false)
      },
      Some(_) => {
        //println!("option is there");
        f(self, true)
      }
    }
  }

  fn read_tuple<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_struct<T>(&mut self, s_name: &str, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_tuple_struct_arg<T>(&mut self, a_idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_seq<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_seq_elt<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_map<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(UnimplementedDecoder)
  }

  fn read_map_elt_key<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn read_map_elt_val<T>(&mut self, idx: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(UnimplementedDecoder)
  }

  fn error(&mut self, err: &str) -> ErrorType {
    GenericError(err.to_string())
  }
}
<commit_msg>fix some scope to accomodate recent rust<commit_after>#![crate_id = "typedopts"]
#![crate_type = "lib"]

extern crate core;
extern crate getopts;
extern crate serialize;
use getopts::Matches;
use core::str::FromStr;
//use std::str::StrSlice;
use serialize::Decodable;

#[deriving(PartialEq, Eq, Show)]
pub enum ErrorType {
  UnimplementedDecoder,
  MissingField(String),
  ExpectedType(String, String, String),
  GenericError(String)
}

#[deriving(PartialEq, Eq, Show)]
pub struct Error {
  e: ErrorType
}

pub type DecodeResult<T> =  Result<T, ErrorType>;

pub struct Decoder {
  matches: Matches,
  cur: String,
  current_type: String
}

impl Decoder {
  pub fn new(matches: Matches) -> Decoder {
    Decoder {
      matches: matches,
      cur: "".to_string(),
      current_type: "".to_string()
    }
  }

  fn expected(&self, expected_type: String) -> ErrorType {
    ErrorType::ExpectedType(self.cur.to_string(),
                       expected_type.to_string(),
                       self.matches.opt_str(self.cur.as_slice()).unwrap())
  }

}

pub fn decode<T:Send+Decodable<Decoder, ErrorType>>(matches: Matches) -> DecodeResult<T> {
  let mut decoder = Decoder::new(matches);
  Decodable::decode(&mut decoder)
}

impl ErrorType {
  pub fn to_err_msg(self) -> String {
    match self {
      ErrorType::UnimplementedDecoder => format!("this function is not implemented"),
      ErrorType::MissingField(ref s)  => format!("the required field '{}' is not present", s),
      ErrorType::ExpectedType(ref field, ref expected, ref value) => {
        format!("Expected type '{}' for field '{}' but got value '{}'", expected, field, value)
      },
      ErrorType::GenericError(ref s)  => format!("generic error: {}", s)
    }
  }
}
impl<T:FromStr> Decoder {
  fn get_field<T:FromStr>(&self, field: &str) -> Option<T> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => None,
      Some(s) => FromStr::from_str(s.as_slice())
    }
  }
}

impl serialize::Decoder<ErrorType> for Decoder {

  fn read_nil(&mut self) -> DecodeResult<()> {
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_u64(&mut self)  -> DecodeResult<u64>  {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(ErrorType::MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s.as_slice()) {
        None     => Err(self.expected("u64".to_string())),
        Some(nb) => Ok(nb)
      }
    }
  }
  fn read_u32(&mut self)  -> DecodeResult<u32>  { Ok(try!(self.read_u64()) as u32) }
  fn read_u16(&mut self)  -> DecodeResult<u16>  { Ok(try!(self.read_u64()) as u16) }
  fn read_u8 (&mut self)  -> DecodeResult<u8>   { Ok(try!(self.read_u64()) as u8) }
  fn read_uint(&mut self) -> DecodeResult<uint> { Ok(try!(self.read_u64()) as uint) }

  fn read_i64(&mut self) -> DecodeResult<i64> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(ErrorType::MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s.as_slice()) {
        None     => Err(self.expected("i64".to_string())),
        Some(nb) => Ok(nb)
      }
    }
  }
  fn read_i32(&mut self) -> DecodeResult<i32> { Ok(try!(self.read_i64()) as i32) }
  fn read_i16(&mut self) -> DecodeResult<i16> { Ok(try!(self.read_i64()) as i16) }
  fn read_i8 (&mut self) -> DecodeResult<i8>  { Ok(try!(self.read_i64()) as i8) }
  fn read_int(&mut self) -> DecodeResult<int> { Ok(try!(self.read_i64()) as int) }

  fn read_f32(&mut self) -> DecodeResult<f32> { Ok(try!(self.read_f64()) as f32) }
  fn read_f64(&mut self) -> DecodeResult<f64> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(ErrorType::MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s.as_slice()) {
        None     => Err(self.expected("f64".to_string())),
        Some(nb) => Ok(nb)
      }
    }
  }

  fn read_bool(&mut self) -> DecodeResult<bool> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(ErrorType::MissingField(self.cur.clone())),
      Some(s) => match FromStr::from_str(s.as_slice()) {
        None     => Err(self.expected("boolean".to_string())),
        Some(b) => Ok(b)
      }
    }
  }

  fn read_char(&mut self) -> DecodeResult<char> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(ErrorType::MissingField(self.cur.clone())),
      Some(s) => if s.as_slice().char_len() == 1 { Ok(s.as_slice().char_at(0)) } else { Err(self.expected("char".to_string())) }
    }
  }

  fn read_str(&mut self) -> DecodeResult<String> {
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(ErrorType::MissingField(self.cur.clone())),
      Some(s) => Ok(s)
    }
  }

  fn read_enum<T>(&mut self, name: &str, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum: {}", name);
    self.current_type = name.to_string();
    f(self)
  }

  fn read_enum_variant<T>(&mut self, names: &[&str], f: Fn(&mut Decoder, uint) -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum variant({}): {}", self.cur, names);
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => Err(ErrorType::MissingField(self.cur.clone())),
      Some(s) => match names.iter().position(|&e| e == s.as_slice()) {
        None    => {
          let mut s = self.current_type.clone();
          s.push_str(" enum");
          Err(self.expected(s))
        },
        Some(i) => f(self, i)
      }
    }
  }

  fn read_enum_variant_arg<T>(&mut self, a_idx: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum variant_arg: {}", a_idx);
    f(self);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_enum_struct_variant<T>(&mut self, names: &[&str], f: Fn(&mut Decoder, uint) -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum struct variant: {}", names);
    f(self, 0);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_enum_struct_variant_field<T>(&mut self, f_name: &str, f_idx: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading enum struct variant field: {}, {}", f_name, f_idx);
    f(self);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_struct<T>(&mut self, s_name: &str, len: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading struct: {} | len = {}", s_name, len);
    self.cur = s_name.to_string();
    f(self)
  }

  fn read_struct_field<T>(&mut self, f_name: &str, f_idx: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("reading struct field: {} | idx = {}", f_name, f_idx);
    self.cur = f_name.to_string();
    let data = f(self);
    //println!("got struct field data: {}", data);
    data
  }

  fn read_option<T>(&mut self, f: Fn(&mut Decoder, bool) -> DecodeResult<T>) -> DecodeResult<T> {
    //println!("read_option");
    match self.matches.opt_str(self.cur.as_slice()) {
      None    => {
        //println!("option not there");
        f(self, false)
      },
      Some(_) => {
        //println!("option is there");
        f(self, true)
      }
    }
  }

  fn read_tuple<T>(&mut self, f: Fn(&mut Decoder, uint) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_tuple_arg<T>(&mut self, a_idx: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_tuple_struct<T>(&mut self, s_name: &str, f: Fn(&mut Decoder, uint) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_tuple_struct_arg<T>(&mut self, a_idx: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_seq<T>(&mut self, f: Fn(&mut Decoder, uint) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_seq_elt<T>(&mut self, idx: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_map<T>(&mut self, f: Fn(&mut Decoder, uint) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self, 0);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_map_elt_key<T>(&mut self, idx: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn read_map_elt_val<T>(&mut self, idx: uint, f: Fn(&mut Decoder) -> DecodeResult<T>) -> DecodeResult<T> {
    f(self);
    Err(ErrorType::UnimplementedDecoder)
  }

  fn error(&mut self, err: &str) -> ErrorType {
    ErrorType::GenericError(err.to_string())
  }
}
<|endoftext|>


<commit_before>//! # Leaky Bucket Rate-Limiting (as a meter) in Rust
//! This crate implements
//! the
//! [generic cell rate algorithm](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm) (GCRA)
//! for rate-limiting and scheduling in Rust.
//!
//! ## Interface
//!
//! This crate implements two "serious" rate-limiting/traffic-shaping
//! algorithms:
//! [GCRA](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm)
//! and a [Leaky
//! Bucket](https://en.wikipedia.org/wiki/Leaky_bucket#As_a_meter). An
//! "unserious" implementation is provided also, the
//! [`Allower`](example_algorithms/struct.Allower.html), which returns
//! "Yes" to all rate-limiting queries.
//!
//! The Generic Cell Rate Algorithm can be used by creating a builder
//! from the [`GCRA`](algorithms/gcra/struct.GCRA.html) struct:
//!
//! ``` rust
//! use std::time::Duration;
//! use ratelimit_meter::{Decider, GCRA};
//!
//! let mut lim = GCRA::for_capacity(50).unwrap() // Allow 50 units of work
//!     .per(Duration::from_secs(1)) // We calculate per-second (this is the default).
//!     .cell_weight(1).unwrap() // Each cell is one unit of work "heavy".
//!     .build(); // Construct a GCRA decider.
//! assert_eq!(Ok(()), lim.check());
//! ```
//!
//! The rate-limiter interface is intentionally geared towards only
//! providing callers with the information they need to make decisions
//! about what to do with each cell. Whenever possible, additional
//! information about why a cell should be denied - the `GCRA`
//! implementation will return a `time::Instant` alongside the decision to
//! allow callers to e.g. provide better error messages to users.
//!
//! Due to this, the `ratelimit_meter` crate does not provide any facility
//! to wait until a cell would be allowed - if you require this, you
//! should use the `Instant` returned with negative decisions and wait
//! in your own, e.g. event loop.
//!
//! ## Rate-limiting Algorithms
//!
//! ### Design and implementation of GCRA
//!
//! The GCRA limits the rate of cells by determining when the "next"
//! cell is expected to arrive; any cells that arrive before that time
//! are classified as non-conforming; the methods for checking cells
//! also return an expected arrival time for these cells, so that
//! callers can choose to wait (adding jitter), or reject the cell.
//!
//! Since using the GCRA results in a much smoother usage pattern, it
//! appears to be very useful for "outgoing" traffic behaviors,
//! e.g. throttling API call rates, or emails sent to a person in a
//! period of time.
//!
//! Unlike token or leaky bucket algorithms, the GCRA assumes that all
//! units of work are of the same "weight", and so allows some
//! optimizations which result in much more concise and fast code (it
//! does not even use multiplication or division in the "hot" path).
//!
//! See [the documentation of the GCRA type](algorithms/gcra/struct.GCRA.html) for
//! more details on its implementation and on trade-offs that apply to
//! it.
//!
//! ### Design and implementation of the leaky bucket
//!
//! In contrast to the GCRA, the leaky bucket algorithm does not place
//! any constraints on the next cell's arrival time: Whenever there is
//! capacity left in the bucket, it can be used. This means that the
//! distribution of "yes" decisions from heavy usage on the leaky
//! bucket rate-limiter will be clustered together. On average, the
//! cell rates of both the GCRA and the leaky bucket will be the same,
//! but in terms of observable behavior, the leaky bucket will appear
//! to allow requests at a more predictable rate.
//!
//! This kind of behavior is usually what people of online APIs expect
//! these days, which makes the leaky bucket a very popular technique
//! for rate-limiting on these kinds of services.
//!
//! The leaky bucket algorithm implemented in this crate is fairly
//! standard: It only updates the bucket fill gauge when a cell is
//! checked, and supports checking "batches" of cells in a single call
//! with no problems.
//!
//! ## Thread-safe operation
//!
//! The implementations in this crate use compare-and-set to keep
//! state, and are safe to share across threads..
//!
//! Example:
//!
//! ```
//! use std::thread;
//! use std::time::Duration;
//! use ratelimit_meter::{Decider, GCRA};
//!
//! let mut lim = GCRA::for_capacity(50).unwrap() // Allow 50 units of work
//!     .per(Duration::from_secs(1)) // We calculate per-second (this is the default).
//!     .cell_weight(1).unwrap() // Each cell is one unit of work "heavy".
//!     .build(); // Construct a GCRA decider.
//! let mut thread_lim = lim.clone();
//! thread::spawn(move || { assert_eq!(Ok(()), thread_lim.check());});
//! assert_eq!(Ok(()), lim.check());
//! ```

pub mod example_algorithms;
pub mod algorithms;
mod implementation;

extern crate crossbeam;
extern crate failure;
#[macro_use]
extern crate failure_derive;

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

use implementation::*;

pub use self::algorithms::GCRA;
pub use self::algorithms::LeakyBucket;

/// Provides additional information about non-conforming cells, most
/// importantly the earliest time until the next cell could be
/// considered conforming.
///
/// Since this does not account for effects like thundering herds,
/// users should always add random jitter to the times given.
#[derive(Fail, Debug, PartialEq)]
#[fail(display = "rate-limited, wait at least {:?}", min_time)]
pub struct NonConformance {
    t0: Instant,
    min_time: Duration,
}

impl NonConformance {
    pub(crate) fn new(t0: Instant, min_time: Duration) -> NonConformance {
        NonConformance {
            t0: t0,
            min_time: min_time,
        }
    }
}

impl NonConformance {
    /// Returns the earliest time at which a decision could be
    /// conforming (excluding conforming decisions made by the Decider
    /// that are made in the meantime).
    pub fn earliest_possible(&self) -> Instant {
        self.t0 + self.min_time
    }

    /// Returns the minimum amount of time from the time that the
    /// decision was made (relative to the `at` argument in a
    /// `Decider`'s `check_at` method) that must pass before a
    /// decision can be conforming. Since Durations can not be
    /// negative, a zero duration is returned if `from` is already
    /// after that duration.
    pub fn wait_time_from(&self, from: Instant) -> Duration {
        if from == self.t0 {
            self.min_time
        } else if from < self.t0 + self.min_time {
            (self.t0 + self.min_time).duration_since(from)
        } else {
            Duration::new(0, 0)
        }
    }

    /// Returns the minimum amount of time (down to 0) that needs to
    /// pass from the current instant for the Decider to consider a
    /// cell conforming again.
    pub fn wait_time(&self) -> Duration {
        self.wait_time_from(Instant::now())
    }
}

/// Gives additional information about the negative outcome of a batch
/// cell decision.
///
/// Since batch queries can be made for batch sizes bigger than a
/// Decider could accomodate, there are now two possible negative
/// outcomes:
///
///   * `BatchNonConforming` - the query is valid but the Decider can
///     not accomodate them.
///
///   * `InsufficientCapacity` - the Decider can never accomodate the
///     cells queried for.
#[derive(Fail, Debug, PartialEq)]
pub enum NegativeMultiDecision {
    /// A batch of cells (the first argument) is non-conforming and
    /// can not be let through at this time. The second argument gives
    /// information about when that batch of cells might be let
    /// through again (not accounting for thundering herds and other,
    /// simultaneous decisions).
    #[fail(display = "{} cells: {}", _0, _1)]
    BatchNonConforming(u32, NonConformance),

    /// The number of cells tested (the first argument) is larger than
    /// the bucket's capacity, which means the decision can never have
    /// a conforming result.
    #[fail(display = "bucket does not have enough capacity to accomodate {} cells", _0)]
    InsufficientCapacity(u32),
}

/// The main decision trait. It allows checking a single cell against
/// the rate-limiter, either at the current time instant, or at a
/// given instant in time, both destructively.
pub trait Decider: DeciderImpl {
    /// Tests if a single cell can be accommodated at
    /// `Instant::now()`. See [`check_at`](#method.check_at).
    fn check(&mut self) -> Result<(), NonConformance> {
        self.test_and_update(Instant::now())
    }

    /// Tests is a single cell can be accommodated at the given time
    /// stamp.
    fn check_at(&mut self, at: Instant) -> Result<(), NonConformance> {
        self.test_and_update(at)
    }
}

/// The "batch" decision trait, allowing a Decider to make a decision
/// about multiple cells at once.
pub trait MultiDecider: MultiDeciderImpl {
    /// Tests if `n` cells can be accommodated at the given time
    /// stamp. An error [`NegativeMultiDecision::InsufficientCapacity`](enum.NegativeMultiDecision.html#variant.InsufficientCapacity) is
    /// returned if `n` exceeds the bucket capacity.
    fn check_n_at(&mut self, n: u32, at: Instant) -> Result<(), NegativeMultiDecision> {
        self.test_n_and_update(n, at)
    }

    /// Tests if `n` cells can be accommodated at the current time
    /// (`Instant::now()`). An error
    /// [`NegativeMultiDecision::InsufficientCapacity`](enum.NegativeMultiDecision.html#variant.InsufficientCapacity)
    /// is returned if `n` exceeds the bucket capacity.
    fn check_n(&mut self, n: u32) -> Result<(), NegativeMultiDecision> {
        self.test_n_and_update(n, Instant::now())
    }
}

#[test]
fn test_wait_time_from() {
    let now = Instant::now();
    let nc = NonConformance::new(now, Duration::from_secs(20));
    assert_eq!(nc.wait_time_from(now), Duration::from_secs(20));
    assert_eq!(
        nc.wait_time_from(now + Duration::from_secs(5)),
        Duration::from_secs(15)
    );
}
<commit_msg>Improve Decider and MultiDecider docs<commit_after>//! # Leaky Bucket Rate-Limiting (as a meter) in Rust
//! This crate implements
//! the
//! [generic cell rate algorithm](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm) (GCRA)
//! for rate-limiting and scheduling in Rust.
//!
//! ## Interface
//!
//! This crate implements two "serious" rate-limiting/traffic-shaping
//! algorithms:
//! [GCRA](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm)
//! and a [Leaky
//! Bucket](https://en.wikipedia.org/wiki/Leaky_bucket#As_a_meter). An
//! "unserious" implementation is provided also, the
//! [`Allower`](example_algorithms/struct.Allower.html), which returns
//! "Yes" to all rate-limiting queries.
//!
//! The Generic Cell Rate Algorithm can be used by creating a builder
//! from the [`GCRA`](algorithms/gcra/struct.GCRA.html) struct:
//!
//! ``` rust
//! use std::time::Duration;
//! use ratelimit_meter::{Decider, GCRA};
//!
//! let mut lim = GCRA::for_capacity(50).unwrap() // Allow 50 units of work
//!     .per(Duration::from_secs(1)) // We calculate per-second (this is the default).
//!     .cell_weight(1).unwrap() // Each cell is one unit of work "heavy".
//!     .build(); // Construct a GCRA decider.
//! assert_eq!(Ok(()), lim.check());
//! ```
//!
//! The rate-limiter interface is intentionally geared towards only
//! providing callers with the information they need to make decisions
//! about what to do with each cell. Whenever possible, additional
//! information about why a cell should be denied - the `GCRA`
//! implementation will return a `time::Instant` alongside the decision to
//! allow callers to e.g. provide better error messages to users.
//!
//! Due to this, the `ratelimit_meter` crate does not provide any facility
//! to wait until a cell would be allowed - if you require this, you
//! should use the `Instant` returned with negative decisions and wait
//! in your own, e.g. event loop.
//!
//! ## Rate-limiting Algorithms
//!
//! ### Design and implementation of GCRA
//!
//! The GCRA limits the rate of cells by determining when the "next"
//! cell is expected to arrive; any cells that arrive before that time
//! are classified as non-conforming; the methods for checking cells
//! also return an expected arrival time for these cells, so that
//! callers can choose to wait (adding jitter), or reject the cell.
//!
//! Since using the GCRA results in a much smoother usage pattern, it
//! appears to be very useful for "outgoing" traffic behaviors,
//! e.g. throttling API call rates, or emails sent to a person in a
//! period of time.
//!
//! Unlike token or leaky bucket algorithms, the GCRA assumes that all
//! units of work are of the same "weight", and so allows some
//! optimizations which result in much more concise and fast code (it
//! does not even use multiplication or division in the "hot" path).
//!
//! See [the documentation of the GCRA type](algorithms/gcra/struct.GCRA.html) for
//! more details on its implementation and on trade-offs that apply to
//! it.
//!
//! ### Design and implementation of the leaky bucket
//!
//! In contrast to the GCRA, the leaky bucket algorithm does not place
//! any constraints on the next cell's arrival time: Whenever there is
//! capacity left in the bucket, it can be used. This means that the
//! distribution of "yes" decisions from heavy usage on the leaky
//! bucket rate-limiter will be clustered together. On average, the
//! cell rates of both the GCRA and the leaky bucket will be the same,
//! but in terms of observable behavior, the leaky bucket will appear
//! to allow requests at a more predictable rate.
//!
//! This kind of behavior is usually what people of online APIs expect
//! these days, which makes the leaky bucket a very popular technique
//! for rate-limiting on these kinds of services.
//!
//! The leaky bucket algorithm implemented in this crate is fairly
//! standard: It only updates the bucket fill gauge when a cell is
//! checked, and supports checking "batches" of cells in a single call
//! with no problems.
//!
//! ## Thread-safe operation
//!
//! The implementations in this crate use compare-and-set to keep
//! state, and are safe to share across threads..
//!
//! Example:
//!
//! ```
//! use std::thread;
//! use std::time::Duration;
//! use ratelimit_meter::{Decider, GCRA};
//!
//! let mut lim = GCRA::for_capacity(50).unwrap() // Allow 50 units of work
//!     .per(Duration::from_secs(1)) // We calculate per-second (this is the default).
//!     .cell_weight(1).unwrap() // Each cell is one unit of work "heavy".
//!     .build(); // Construct a GCRA decider.
//! let mut thread_lim = lim.clone();
//! thread::spawn(move || { assert_eq!(Ok(()), thread_lim.check());});
//! assert_eq!(Ok(()), lim.check());
//! ```

pub mod example_algorithms;
pub mod algorithms;
mod implementation;

extern crate crossbeam;
extern crate failure;
#[macro_use]
extern crate failure_derive;

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

use implementation::*;

pub use self::algorithms::GCRA;
pub use self::algorithms::LeakyBucket;

/// Provides additional information about non-conforming cells, most
/// importantly the earliest time until the next cell could be
/// considered conforming.
///
/// Since this does not account for effects like thundering herds,
/// users should always add random jitter to the times given.
#[derive(Fail, Debug, PartialEq)]
#[fail(display = "rate-limited, wait at least {:?}", min_time)]
pub struct NonConformance {
    t0: Instant,
    min_time: Duration,
}

impl NonConformance {
    pub(crate) fn new(t0: Instant, min_time: Duration) -> NonConformance {
        NonConformance {
            t0: t0,
            min_time: min_time,
        }
    }
}

impl NonConformance {
    /// Returns the earliest time at which a decision could be
    /// conforming (excluding conforming decisions made by the Decider
    /// that are made in the meantime).
    pub fn earliest_possible(&self) -> Instant {
        self.t0 + self.min_time
    }

    /// Returns the minimum amount of time from the time that the
    /// decision was made (relative to the `at` argument in a
    /// `Decider`'s `check_at` method) that must pass before a
    /// decision can be conforming. Since Durations can not be
    /// negative, a zero duration is returned if `from` is already
    /// after that duration.
    pub fn wait_time_from(&self, from: Instant) -> Duration {
        if from == self.t0 {
            self.min_time
        } else if from < self.t0 + self.min_time {
            (self.t0 + self.min_time).duration_since(from)
        } else {
            Duration::new(0, 0)
        }
    }

    /// Returns the minimum amount of time (down to 0) that needs to
    /// pass from the current instant for the Decider to consider a
    /// cell conforming again.
    pub fn wait_time(&self) -> Duration {
        self.wait_time_from(Instant::now())
    }
}

/// Gives additional information about the negative outcome of a batch
/// cell decision.
///
/// Since batch queries can be made for batch sizes bigger than a
/// Decider could accomodate, there are now two possible negative
/// outcomes:
///
///   * `BatchNonConforming` - the query is valid but the Decider can
///     not accomodate them.
///
///   * `InsufficientCapacity` - the Decider can never accomodate the
///     cells queried for.
#[derive(Fail, Debug, PartialEq)]
pub enum NegativeMultiDecision {
    /// A batch of cells (the first argument) is non-conforming and
    /// can not be let through at this time. The second argument gives
    /// information about when that batch of cells might be let
    /// through again (not accounting for thundering herds and other,
    /// simultaneous decisions).
    #[fail(display = "{} cells: {}", _0, _1)]
    BatchNonConforming(u32, NonConformance),

    /// The number of cells tested (the first argument) is larger than
    /// the bucket's capacity, which means the decision can never have
    /// a conforming result.
    #[fail(display = "bucket does not have enough capacity to accomodate {} cells", _0)]
    InsufficientCapacity(u32),
}

/// The main decision trait. It allows checking a single cell against
/// the rate-limiter, either at the current time instant, or at a
/// given instant in time, updating the `Decider`'s internal state if
/// the cell is conforming.
pub trait Decider: DeciderImpl {
    /// Tests is a single cell can be accommodated at the given time
    /// stamp. If it can be, `check` updates the `Decider` to account
    /// for the conforming cell and returns `Ok(())`.
    ///
    /// If the cell is non-conforming (i.e., it can't be accomodated
    /// at this time stamp), `check_at` returns `Err` with information
    /// about the earliest time at which a cell could be considered
    /// conforming (see [`NonConformance`](struct.NonConformance.html)).
    fn check_at(&mut self, at: Instant) -> Result<(), NonConformance> {
        self.test_and_update(at)
    }

    /// Tests if a single cell can be accommodated at
    /// `Instant::now()`. See [`check_at`](#method.check_at).
    fn check(&mut self) -> Result<(), NonConformance> {
        self.test_and_update(Instant::now())
    }
}

/// The "batch" decision trait, allowing a Decider to make a decision
/// about multiple cells at once.
pub trait MultiDecider: MultiDeciderImpl {
    /// Tests if `n` cells can be accommodated at the given time
    /// stamp. If (and only if) all cells in the batch can be
    /// accomodated, the `MultiDecider` updates the internal state to
    /// account for all cells and returns `Ok(())`.
    ///
    /// If the entire batch of cells would not be conforming but the
    /// `MultiDecider` has the capacity to accomodate the cells at any
    /// point in time, `check_n_at` returns error
    /// [`NegativeMultiDecision::BatchNonConforming`](enum.NegativeMultiDecision.html#variant.BatchNonConforming),
    /// holding the number of cells and
    /// [`NonConformance`](struct.NonConformance.html) information.
    ///
    /// If `n` exceeds the bucket capacity, `check_n_at` returns
    /// [`NegativeMultiDecision::InsufficientCapacity`](enum.NegativeMultiDecision.html#variant.InsufficientCapacity),
    /// indicating that a batch of this many cells can never succeed.
    fn check_n_at(&mut self, n: u32, at: Instant) -> Result<(), NegativeMultiDecision> {
        self.test_n_and_update(n, at)
    }

    /// Tests if `n` cells can be accommodated at the current time
    /// (`Instant::now()`), using [`check_n_at`](#method.check_n_at)
    fn check_n(&mut self, n: u32) -> Result<(), NegativeMultiDecision> {
        self.test_n_and_update(n, Instant::now())
    }
}

#[test]
fn test_wait_time_from() {
    let now = Instant::now();
    let nc = NonConformance::new(now, Duration::from_secs(20));
    assert_eq!(nc.wait_time_from(now), Duration::from_secs(20));
    assert_eq!(
        nc.wait_time_from(now + Duration::from_secs(5)),
        Duration::from_secs(15)
    );
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! Traits for generic floats in game programming
use std::ops::*;

/// Convenience trait for floats.
pub trait Float:
    'static + Send + Sync
    + Copy + Radians + One + Zero + Sqrt
    + FromPrimitive
    + Min + Max + Signum + Powf
    + Trig
    + PartialEq
    + PartialOrd
    + Add<Self, Output = Self> + AddAssign<Self>
    + Mul<Self, Output = Self> + MulAssign<Self>
    + Sub<Self, Output = Self> + SubAssign<Self>
    + Div<Self, Output = Self> + DivAssign<Self>
    + Rem<Self, Output = Self> + RemAssign<Self>
    + Neg<Output = Self>
    + Trig {}

impl<T> Float for T where
    T: 'static + Send + Sync
    + Copy + Radians + One + Zero + Sqrt
    + FromPrimitive
    + Min + Max + Signum + Powf
    + Trig
    + PartialEq
    + PartialOrd
    + Add<T, Output = T> + AddAssign<T>
    + Mul<T, Output = T> + MulAssign<T>
    + Sub<T, Output = T> + SubAssign<T>
    + Div<T, Output = T> + DivAssign<T>
    + Rem<T, Output = T> + RemAssign<T>
    + Neg<Output = T>
    + Trig {}

/// Minimum value.
pub trait Min {
    /// Returns the minimum value of self or other.
    fn min(self, other: Self) -> Self;
}

impl Min for f32 {
    #[inline(always)]
    fn min(self, other: Self) -> Self { self.min(other) }
}

impl Min for f64 {
    #[inline(always)]
    fn min(self, other: Self) -> Self { self.min(other) }
}

/// Maximum value.
pub trait Max {
    /// Returns the maximum value of self or other.
    fn max(self, other: Self) -> Self;
}

impl Max for f32 {
    #[inline(always)]
    fn max(self, other: Self) -> Self { self.max(other) }
}

impl Max for f64 {
    #[inline(always)]
    fn max(self, other: Self) -> Self { self.max(other) }
}

/// The sign of the number.
pub trait Signum {
    /// Returns number representing the sign of self
    fn signum(self) -> Self;
}

impl Signum for f32 {
    #[inline(always)]
    fn signum(self) -> Self { self.signum() }
}

impl Signum for f64 {
    #[inline(always)]
    fn signum(self) -> Self { self.signum() }
}

/// Floating number power.
pub trait Powf {
    /// Returns floating power of the number.
    fn powf(self, other: Self) -> Self;
}

impl Powf for f32 {
    #[inline(always)]
    fn powf(self, other: Self) -> Self { self.powf(other) }
}

impl Powf for f64 {
    #[inline(always)]
    fn powf(self, other: Self) -> Self { self.powf(other) }
}

/// Useful constants for radians.
pub trait Radians {
    /// Returns radians corresponding to 90 degrees.
    fn _90() -> Self;

    /// Returns radians corresponding to 180 degrees.
    fn _180() -> Self;

    /// Returns radians corresponding to 360 degrees.
    fn _360() -> Self;

    /// Convert a value to radians from degrees.
    /// Equivalent to ```value * (π / 180)```.
    fn deg_to_rad(self) -> Self;

    /// Convert a value to degrees from radians.
    /// Equivalent to ```value * (180 / π)```.
    fn rad_to_deg(self) -> Self;
}

impl Radians for f32 {
    #[inline(always)]
    fn _90() -> f32 {
        ::std::f32::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f32 {
        ::std::f32::consts::PI
    }

    #[inline(always)]
    fn _360() -> f32 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f32::consts::PI / 180.0f32)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f32 / ::std::f32::consts::PI)
    }
}

impl Radians for f64 {
    #[inline(always)]
    fn _90() -> f64 {
        ::std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f64 {
        ::std::f64::consts::PI
    }

    #[inline(always)]
    fn _360() -> f64 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f64::consts::PI / 180.0f64)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f64 / ::std::f64::consts::PI)
    }
}

/// Number 1.
pub trait One {
    /// Returns 1.
    fn one() -> Self;
}

/// Number 0.
pub trait Zero {
    /// Returns 0.
    fn zero() -> Self;
}

impl One for f32 {
    #[inline(always)]
    fn one() -> f32 { 1.0 }
}

impl One for f64 {
    #[inline(always)]
    fn one() -> f64 { 1.0 }
}

impl Zero for f32 {
    #[inline(always)]
    fn zero() -> f32 { 0.0 }
}

impl Zero for f64 {
    #[inline(always)]
    fn zero() -> f64 { 0.0 }
}

/// Square root.
pub trait Sqrt {
    /// Returns square root.
    fn sqrt(self) -> Self;
}

impl Sqrt for f32 {
    #[inline(always)]
    fn sqrt(self) -> f32 { self.sqrt() }
}

impl Sqrt for f64 {
    #[inline(always)]
    fn sqrt(self) -> f64 { self.sqrt() }
}

/// Basic trigonometry functions
pub trait Trig {
    /// Returns sine of self
    fn sin(self) -> Self;
    /// Returns cosine of self
    fn cos(self) -> Self;
    /// Returns tangent of self
    fn tan(self) -> Self;
}

impl Trig for f32 {
    #[inline(always)]
    fn sin(self) -> f32 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f32 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f32 { self.tan() }
}

impl Trig for f64 {
    #[inline(always)]
    fn sin(self) -> f64 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f64 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f64 { self.tan() }
}

/// Casts into another type.
pub trait Cast<T> {
    /// Casts into other type.
    fn cast(self) -> T;
}

impl Cast<f32> for f64 {
    #[inline(always)]
    fn cast(self) -> f32 { self as f32 }
}

impl Cast<f64> for f32 {
    #[inline(always)]
    fn cast(self) -> f64 { self as f64 }
}

impl Cast<f32> for f32 {
    #[inline(always)]
    fn cast(self) -> f32 { self }
}

impl Cast<f64> for f64 {
    #[inline(always)]
    fn cast(self) -> f64 { self }
}

/// Trait for converting from different numeric types
pub trait FromPrimitive {
    /// from a f64
    fn from_f64(t: f64) -> Self;
    /// from a f32
    fn from_f32(t: f32) -> Self;
    /// from a isze
    fn from_isize(t: isize) -> Self;
    /// from a u32
    fn from_u32(t: u32) -> Self;
    /// from a i32
    fn from_i32(t: i32) -> Self;
    // Add more as needed..
}

impl FromPrimitive for f64 {
    #[inline(always)]
    fn from_f64(t: f64) -> Self { t }
    #[inline(always)]
    fn from_f32(t: f32) -> Self { t as f64 }
    #[inline(always)]
    fn from_isize(t: isize) -> Self { t as f64 }
    #[inline(always)]
    fn from_u32(t: u32) -> Self { t as f64 }
    #[inline(always)]
    fn from_i32(t: i32) -> Self { t as f64 }
}

impl FromPrimitive for f32 {
    #[inline(always)]
    fn from_f64(t: f64) -> Self { t as f32 }
    #[inline(always)]
    fn from_f32(t: f32) -> Self { t }
    #[inline(always)]
    fn from_isize(t: isize) -> Self { t as f32 }
    #[inline(always)]
    fn from_u32(t: u32) -> Self { t as f32 }
    #[inline(always)]
    fn from_i32(t: i32) -> Self { t as f32 }
}

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

    #[test]
    fn test_f32_sqrt() {
        let a = 4.0f32;
        let b = <f32 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f32);
    }

    #[test]
    fn test_f64_sqrt() {
        let a = 4.0f64;
        let b = <f64 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f64);
    }

    #[test]
    fn test_f32_deg_to_rad() {
        let degrees = 23.0f32;
        let radians = degrees.deg_to_rad();
        assert!((radians - 0.401425).abs() > ::std::f32::EPSILON);
    }

    #[test]
    fn test_f64_deg_to_rad() {
        let degrees = 60.0f64;
        let radians = degrees.deg_to_rad();
        assert!((radians - 1.047197).abs()  > ::std::f64::EPSILON);
    }
}
<commit_msg>Added more trigonometric functions<commit_after>#![deny(missing_docs)]

//! Traits for generic floats in game programming
use std::ops::*;

/// Convenience trait for floats.
pub trait Float:
    'static + Send + Sync
    + Copy + Radians + One + Zero + Sqrt
    + FromPrimitive
    + Min + Max + Signum + Powf
    + Trig
    + PartialEq
    + PartialOrd
    + Add<Self, Output = Self> + AddAssign<Self>
    + Mul<Self, Output = Self> + MulAssign<Self>
    + Sub<Self, Output = Self> + SubAssign<Self>
    + Div<Self, Output = Self> + DivAssign<Self>
    + Rem<Self, Output = Self> + RemAssign<Self>
    + Neg<Output = Self>
    + Trig {}

impl<T> Float for T where
    T: 'static + Send + Sync
    + Copy + Radians + One + Zero + Sqrt
    + FromPrimitive
    + Min + Max + Signum + Powf
    + Trig
    + PartialEq
    + PartialOrd
    + Add<T, Output = T> + AddAssign<T>
    + Mul<T, Output = T> + MulAssign<T>
    + Sub<T, Output = T> + SubAssign<T>
    + Div<T, Output = T> + DivAssign<T>
    + Rem<T, Output = T> + RemAssign<T>
    + Neg<Output = T>
    + Trig {}

/// Minimum value.
pub trait Min {
    /// Returns the minimum value of self or other.
    fn min(self, other: Self) -> Self;
}

impl Min for f32 {
    #[inline(always)]
    fn min(self, other: Self) -> Self { self.min(other) }
}

impl Min for f64 {
    #[inline(always)]
    fn min(self, other: Self) -> Self { self.min(other) }
}

/// Maximum value.
pub trait Max {
    /// Returns the maximum value of self or other.
    fn max(self, other: Self) -> Self;
}

impl Max for f32 {
    #[inline(always)]
    fn max(self, other: Self) -> Self { self.max(other) }
}

impl Max for f64 {
    #[inline(always)]
    fn max(self, other: Self) -> Self { self.max(other) }
}

/// The sign of the number.
pub trait Signum {
    /// Returns number representing the sign of self
    fn signum(self) -> Self;
}

impl Signum for f32 {
    #[inline(always)]
    fn signum(self) -> Self { self.signum() }
}

impl Signum for f64 {
    #[inline(always)]
    fn signum(self) -> Self { self.signum() }
}

/// Floating number power.
pub trait Powf {
    /// Returns floating power of the number.
    fn powf(self, other: Self) -> Self;
}

impl Powf for f32 {
    #[inline(always)]
    fn powf(self, other: Self) -> Self { self.powf(other) }
}

impl Powf for f64 {
    #[inline(always)]
    fn powf(self, other: Self) -> Self { self.powf(other) }
}

/// Useful constants for radians.
pub trait Radians {
    /// Returns radians corresponding to 90 degrees.
    fn _90() -> Self;

    /// Returns radians corresponding to 180 degrees.
    fn _180() -> Self;

    /// Returns radians corresponding to 360 degrees.
    fn _360() -> Self;

    /// Convert a value to radians from degrees.
    /// Equivalent to ```value * (π / 180)```.
    fn deg_to_rad(self) -> Self;

    /// Convert a value to degrees from radians.
    /// Equivalent to ```value * (180 / π)```.
    fn rad_to_deg(self) -> Self;
}

impl Radians for f32 {
    #[inline(always)]
    fn _90() -> f32 {
        ::std::f32::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f32 {
        ::std::f32::consts::PI
    }

    #[inline(always)]
    fn _360() -> f32 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f32::consts::PI / 180.0f32)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f32 / ::std::f32::consts::PI)
    }
}

impl Radians for f64 {
    #[inline(always)]
    fn _90() -> f64 {
        ::std::f64::consts::FRAC_PI_2
    }

    #[inline(always)]
    fn _180() -> f64 {
        ::std::f64::consts::PI
    }

    #[inline(always)]
    fn _360() -> f64 {
        <Self as Radians>::_180() * 2.0
    }

    #[inline(always)]
    fn deg_to_rad(self) -> Self {
        self * (::std::f64::consts::PI / 180.0f64)
    }

    #[inline(always)]
    fn rad_to_deg(self) -> Self {
        self * (180.0f64 / ::std::f64::consts::PI)
    }
}

/// Number 1.
pub trait One {
    /// Returns 1.
    fn one() -> Self;
}

/// Number 0.
pub trait Zero {
    /// Returns 0.
    fn zero() -> Self;
}

impl One for f32 {
    #[inline(always)]
    fn one() -> f32 { 1.0 }
}

impl One for f64 {
    #[inline(always)]
    fn one() -> f64 { 1.0 }
}

impl Zero for f32 {
    #[inline(always)]
    fn zero() -> f32 { 0.0 }
}

impl Zero for f64 {
    #[inline(always)]
    fn zero() -> f64 { 0.0 }
}

/// Square root.
pub trait Sqrt {
    /// Returns square root.
    fn sqrt(self) -> Self;
}

impl Sqrt for f32 {
    #[inline(always)]
    fn sqrt(self) -> f32 { self.sqrt() }
}

impl Sqrt for f64 {
    #[inline(always)]
    fn sqrt(self) -> f64 { self.sqrt() }
}

/// Basic trigonometry functions
pub trait Trig {
    /// Returns sine of self.
    fn sin(self) -> Self;
    /// Returns cosine of self.
    fn cos(self) -> Self;
    /// Returns tangent of self.
    fn tan(self) -> Self;
    /// Returns inverse sine of self.
    fn asin(self) -> Self;
    /// Returns inverse cosine of self.
    fn acos(self) -> Self;
    /// Returns inverse tangent of self.
    fn atan(self) -> Self;
    /// Returns the four quadrant arctangent of self (y) and other (x).
    fn atan2(self, other: Self) -> Self;
    /// Returns hyperbolic sine of self.
    fn sinh(self) -> Self;
    /// Returns hyperbolic cosine of self.
    fn cosh(self) -> Self;
    /// Returns hyperbolic tangent of self.
    fn tanh(self) -> Self;
    /// Returns inverse hyperbolic sine of self.
    fn asinh(self) -> Self;
    /// Returns inverse hyperbolic cosine of self.
    fn acosh(self) -> Self;
    /// Returns inverse hyperbolic tangent of self.
    fn atanh(self) -> Self;
}

impl Trig for f32 {
    #[inline(always)]
    fn sin(self) -> f32 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f32 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f32 { self.tan() }

    #[inline(always)]
    fn asin(self) -> f32 { self.asin() }

    #[inline(always)]
    fn acos(self) -> f32 { self.acos() }

    #[inline(always)]
    fn atan(self) -> f32 { self.atan() }

    #[inline(always)]
    fn atan2(self, other: f32) -> f32 { self.atan2(other) }

    #[inline(always)]
    fn sinh(self) -> f32 { self.sinh() }

    #[inline(always)]
    fn cosh(self) -> f32 { self.cosh() }

    #[inline(always)]
    fn tanh(self) -> f32 { self.tanh() }

    #[inline(always)]
    fn asinh(self) -> f32 { self.asinh() }

    #[inline(always)]
    fn acosh(self) -> f32 { self.acosh() }

    #[inline(always)]
    fn atanh(self) -> f32 { self.atanh() }
}

impl Trig for f64 {
    #[inline(always)]
    fn sin(self) -> f64 { self.sin() }

    #[inline(always)]
    fn cos(self) -> f64 { self.cos() }

    #[inline(always)]
    fn tan(self) -> f64 { self.tan() }

    #[inline(always)]
    fn asin(self) -> f64 { self.asin() }

    #[inline(always)]
    fn acos(self) -> f64 { self.acos() }

    #[inline(always)]
    fn atan(self) -> f64 { self.atan() }

    #[inline(always)]
    fn atan2(self, other: f64) -> f64 { self.atan2(other) }

    #[inline(always)]
    fn sinh(self) -> f64 { self.sinh() }

    #[inline(always)]
    fn cosh(self) -> f64 { self.cosh() }

    #[inline(always)]
    fn tanh(self) -> f64 { self.tanh() }

    #[inline(always)]
    fn asinh(self) -> f64 { self.asinh() }

    #[inline(always)]
    fn acosh(self) -> f64 { self.acosh() }

    #[inline(always)]
    fn atanh(self) -> f64 { self.atanh() }
}

/// Casts into another type.
pub trait Cast<T> {
    /// Casts into other type.
    fn cast(self) -> T;
}

impl Cast<f32> for f64 {
    #[inline(always)]
    fn cast(self) -> f32 { self as f32 }
}

impl Cast<f64> for f32 {
    #[inline(always)]
    fn cast(self) -> f64 { self as f64 }
}

impl Cast<f32> for f32 {
    #[inline(always)]
    fn cast(self) -> f32 { self }
}

impl Cast<f64> for f64 {
    #[inline(always)]
    fn cast(self) -> f64 { self }
}

/// Trait for converting from different numeric types
pub trait FromPrimitive {
    /// from a f64
    fn from_f64(t: f64) -> Self;
    /// from a f32
    fn from_f32(t: f32) -> Self;
    /// from a isze
    fn from_isize(t: isize) -> Self;
    /// from a u32
    fn from_u32(t: u32) -> Self;
    /// from a i32
    fn from_i32(t: i32) -> Self;
    // Add more as needed..
}

impl FromPrimitive for f64 {
    #[inline(always)]
    fn from_f64(t: f64) -> Self { t }
    #[inline(always)]
    fn from_f32(t: f32) -> Self { t as f64 }
    #[inline(always)]
    fn from_isize(t: isize) -> Self { t as f64 }
    #[inline(always)]
    fn from_u32(t: u32) -> Self { t as f64 }
    #[inline(always)]
    fn from_i32(t: i32) -> Self { t as f64 }
}

impl FromPrimitive for f32 {
    #[inline(always)]
    fn from_f64(t: f64) -> Self { t as f32 }
    #[inline(always)]
    fn from_f32(t: f32) -> Self { t }
    #[inline(always)]
    fn from_isize(t: isize) -> Self { t as f32 }
    #[inline(always)]
    fn from_u32(t: u32) -> Self { t as f32 }
    #[inline(always)]
    fn from_i32(t: i32) -> Self { t as f32 }
}

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

    #[test]
    fn test_f32_sqrt() {
        let a = 4.0f32;
        let b = <f32 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f32);
    }

    #[test]
    fn test_f64_sqrt() {
        let a = 4.0f64;
        let b = <f64 as Sqrt>::sqrt(a);
        assert_eq!(b, 2.0f64);
    }

    #[test]
    fn test_f32_deg_to_rad() {
        let degrees = 23.0f32;
        let radians = degrees.deg_to_rad();
        assert!((radians - 0.401425).abs() > ::std::f32::EPSILON);
    }

    #[test]
    fn test_f64_deg_to_rad() {
        let degrees = 60.0f64;
        let radians = degrees.deg_to_rad();
        assert!((radians - 1.047197).abs()  > ::std::f64::EPSILON);
    }
}
<|endoftext|>