<commit_before>use proc_macro2::{Ident, Span, TokenStream};
use std::fmt::Display;
use syn::{
    parse::{Error, Result},
    spanned::Spanned,
    Attribute, Data, DeriveInput, Fields, Lit, Meta, MetaNameValue, NestedMeta,
};

/// Provides the hook to expand `#[derive(Display)]` into an implementation of `From`
pub fn expand(input: &DeriveInput, trait_name: &str) -> Result<TokenStream> {
    let trait_ident = Ident::new(trait_name, Span::call_site());
    let trait_path = &quote!(::std::fmt::#trait_ident);
    let trait_attr = match trait_name {
        "Display" => "display",
        "Binary" => "binary",
        "Octal" => "octal",
        "LowerHex" => "lower_hex",
        "UpperHex" => "upper_hex",
        "LowerExp" => "lower_exp",
        "UpperExp" => "upper_exp",
        "Pointer" => "pointer",
        _ => unimplemented!(),
    };

    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let name = &input.ident;

    let arms = State {
        trait_path,
        trait_attr,
        input,
    }
    .get_match_arms()?;

    Ok(quote! {
        impl #impl_generics #trait_path for #name #ty_generics #where_clause
        {
            #[inline]
            fn fmt(&self, _derive_more_Display_formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                match self {
                    #arms
                }
            }
        }
    })
}

struct State<'a, 'b> {
    trait_path: &'b TokenStream,
    trait_attr: &'static str,
    input: &'a DeriveInput,
}

impl<'a, 'b> State<'a, 'b> {
    fn get_proper_syntax(&self) -> impl Display {
        format!(
            r#"Proper syntax: #[{}(fmt = "My format", "arg1", "arg2")]"#,
            self.trait_attr
        )
    }
    fn get_matcher(&self, fields: &Fields) -> TokenStream {
        match fields {
            Fields::Unit => TokenStream::new(),
            Fields::Unnamed(fields) => {
                let fields: TokenStream = (0..fields.unnamed.len())
                    .map(|n| {
                        let i = Ident::new(&format!("_{}", n), Span::call_site());
                        quote!(#i,)
                    })
                    .collect();
                quote!((#fields))
            }
            Fields::Named(fields) => {
                let fields: TokenStream = fields
                    .named
                    .iter()
                    .map(|f| {
                        let i = f.ident.as_ref().unwrap();
                        quote!(#i,)
                    })
                    .collect();
                quote!({#fields})
            }
        }
    }
    fn find_meta(&self, attrs: &[Attribute]) -> Result<Option<Meta>> {
        let mut it = attrs
            .iter()
            .filter_map(|a| a.interpret_meta())
            .filter(|m| m.name() == self.trait_attr);

        let meta = it.next();
        if it.next().is_some() {
            Err(Error::new(meta.span(), "Too many formats given"))
        } else {
            Ok(meta)
        }
    }
    fn get_meta_fmt(&self, meta: Meta) -> Result<TokenStream> {
        let list = match &meta {
            Meta::List(list) => list,
            _ => return Err(Error::new(meta.span(), self.get_proper_syntax())),
        };

        let fmt = match &list.nested[0] {
            NestedMeta::Meta(Meta::NameValue(MetaNameValue {
                ident,
                lit: Lit::Str(s),
                ..
            }))
                if ident == "fmt" =>
            {
                s
            }
            _ => return Err(Error::new(list.nested[0].span(), self.get_proper_syntax())),
        };

        let args = list
            .nested
            .iter()
            .skip(1) // skip fmt = "..."
            .try_fold(TokenStream::new(), |args, arg| {
                let arg = match arg {
                    NestedMeta::Literal(Lit::Str(s)) => s,
                    NestedMeta::Meta(Meta::Word(i)) => {
                        return Ok(quote_spanned!(list.span()=> #args #i,))
                    }
                    _ => return Err(Error::new(arg.span(), self.get_proper_syntax())),
                };
                let arg: TokenStream = match arg.parse() {
                    Ok(arg) => arg,
                    Err(e) => return Err(Error::new(arg.span(), e)),
                };
                Ok(quote_spanned!(list.span()=> #args #arg,))
            })?;

        Ok(quote_spanned!(meta.span()=> write!(_derive_more_Display_formatter, #fmt, #args)))
    }
    fn infer_fmt(&self, fields: &Fields, name: &Ident) -> Result<TokenStream> {
        let fields = match fields {
            Fields::Unit => {
                return Ok(quote!(write!(
                    _derive_more_Display_formatter,
                    stringify!(#name)
                )));
            }
            Fields::Named(fields) => &fields.named,
            Fields::Unnamed(fields) => &fields.unnamed,
        };
        if fields.len() == 0 {
            return Ok(quote!(write!(
                _derive_more_Display_formatter,
                stringify!(#name)
            )));
        } else if fields.len() > 1 {
            return Err(Error::new(
                fields.span(),
                "Can not automatically infer format for types with more than 1 field",
            ));
        }

        let trait_path = self.trait_path;
        if let Some(ident) = &fields.iter().next().as_ref().unwrap().ident {
            Ok(quote!(#trait_path::fmt(#ident, _derive_more_Display_formatter)))
        } else {
            Ok(quote!(#trait_path::fmt(_0, _derive_more_Display_formatter)))
        }
    }
    fn get_match_arms(&self) -> Result<TokenStream> {
        match &self.input.data {
            Data::Enum(e) => {
                if let Some(meta) = self.find_meta(&self.input.attrs)? {
                    let fmt = self.get_meta_fmt(meta)?;
                    e.variants.iter().try_for_each(|v| {
                        if let Some(meta) = self.find_meta(&v.attrs)? {
                            Err(Error::new(
                                meta.span(),
                                "Can not have a format on the variant when the whole enum has one",
                            ))
                        } else {
                            Ok(())
                        }
                    })?;
                    Ok(quote_spanned!(self.input.span()=> _ => #fmt,))
                } else {
                    e.variants.iter().try_fold(TokenStream::new(), |arms, v| {
                        let matcher = self.get_matcher(&v.fields);
                        let fmt = if let Some(meta) = self.find_meta(&v.attrs)? {
                            self.get_meta_fmt(meta)?
                        } else {
                            self.infer_fmt(&v.fields, &v.ident)?
                        };
                        let name = &self.input.ident;
                        let v_name = &v.ident;
                        Ok(quote_spanned!(self.input.span()=> #arms #name::#v_name #matcher => #fmt,))
                    })
                }
            }
            Data::Struct(s) => {
                let matcher = self.get_matcher(&s.fields);
                let fmt = if let Some(meta) = self.find_meta(&self.input.attrs)? {
                    self.get_meta_fmt(meta)?
                } else {
                    self.infer_fmt(&s.fields, &self.input.ident)?
                };
                let name = &self.input.ident;
                Ok(quote_spanned!(self.input.span()=> #name #matcher => #fmt,))
            }
            Data::Union(_) => {
                let meta = self.find_meta(&self.input.attrs)?.ok_or(Error::new(
                    self.input.span(),
                    "Can not automatically infer format for unions",
                ))?;
                let fmt = self.get_meta_fmt(meta)?;
                Ok(quote_spanned!(self.input.span()=> _ => #fmt,))
            }
        }
    }
}
<commit_msg>Make Display-like derives work for empty enums too<commit_after>use proc_macro2::{Ident, Span, TokenStream};
use std::fmt::Display;
use syn::{
    parse::{Error, Result},
    spanned::Spanned,
    Attribute, Data, DeriveInput, Fields, Lit, Meta, MetaNameValue, NestedMeta,
};

/// Provides the hook to expand `#[derive(Display)]` into an implementation of `From`
pub fn expand(input: &DeriveInput, trait_name: &str) -> Result<TokenStream> {
    let trait_ident = Ident::new(trait_name, Span::call_site());
    let trait_path = &quote!(::std::fmt::#trait_ident);
    let trait_attr = match trait_name {
        "Display" => "display",
        "Binary" => "binary",
        "Octal" => "octal",
        "LowerHex" => "lower_hex",
        "UpperHex" => "upper_hex",
        "LowerExp" => "lower_exp",
        "UpperExp" => "upper_exp",
        "Pointer" => "pointer",
        _ => unimplemented!(),
    };

    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    let name = &input.ident;

    let arms = State {
        trait_path,
        trait_attr,
        input,
    }
    .get_match_arms()?;

    Ok(quote! {
        impl #impl_generics #trait_path for #name #ty_generics #where_clause
        {
            #[inline]
            fn fmt(&self, _derive_more_Display_formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                match self {
                    #arms
                    _ => Ok(()) // This is needed for empty enums
                }
            }
        }
    })
}

struct State<'a, 'b> {
    trait_path: &'b TokenStream,
    trait_attr: &'static str,
    input: &'a DeriveInput,
}

impl<'a, 'b> State<'a, 'b> {
    fn get_proper_syntax(&self) -> impl Display {
        format!(
            r#"Proper syntax: #[{}(fmt = "My format", "arg1", "arg2")]"#,
            self.trait_attr
        )
    }
    fn get_matcher(&self, fields: &Fields) -> TokenStream {
        match fields {
            Fields::Unit => TokenStream::new(),
            Fields::Unnamed(fields) => {
                let fields: TokenStream = (0..fields.unnamed.len())
                    .map(|n| {
                        let i = Ident::new(&format!("_{}", n), Span::call_site());
                        quote!(#i,)
                    })
                    .collect();
                quote!((#fields))
            }
            Fields::Named(fields) => {
                let fields: TokenStream = fields
                    .named
                    .iter()
                    .map(|f| {
                        let i = f.ident.as_ref().unwrap();
                        quote!(#i,)
                    })
                    .collect();
                quote!({#fields})
            }
        }
    }
    fn find_meta(&self, attrs: &[Attribute]) -> Result<Option<Meta>> {
        let mut it = attrs
            .iter()
            .filter_map(|a| a.interpret_meta())
            .filter(|m| m.name() == self.trait_attr);

        let meta = it.next();
        if it.next().is_some() {
            Err(Error::new(meta.span(), "Too many formats given"))
        } else {
            Ok(meta)
        }
    }
    fn get_meta_fmt(&self, meta: Meta) -> Result<TokenStream> {
        let list = match &meta {
            Meta::List(list) => list,
            _ => return Err(Error::new(meta.span(), self.get_proper_syntax())),
        };

        let fmt = match &list.nested[0] {
            NestedMeta::Meta(Meta::NameValue(MetaNameValue {
                ident,
                lit: Lit::Str(s),
                ..
            }))
                if ident == "fmt" =>
            {
                s
            }
            _ => return Err(Error::new(list.nested[0].span(), self.get_proper_syntax())),
        };

        let args = list
            .nested
            .iter()
            .skip(1) // skip fmt = "..."
            .try_fold(TokenStream::new(), |args, arg| {
                let arg = match arg {
                    NestedMeta::Literal(Lit::Str(s)) => s,
                    NestedMeta::Meta(Meta::Word(i)) => {
                        return Ok(quote_spanned!(list.span()=> #args #i,))
                    }
                    _ => return Err(Error::new(arg.span(), self.get_proper_syntax())),
                };
                let arg: TokenStream = match arg.parse() {
                    Ok(arg) => arg,
                    Err(e) => return Err(Error::new(arg.span(), e)),
                };
                Ok(quote_spanned!(list.span()=> #args #arg,))
            })?;

        Ok(quote_spanned!(meta.span()=> write!(_derive_more_Display_formatter, #fmt, #args)))
    }
    fn infer_fmt(&self, fields: &Fields, name: &Ident) -> Result<TokenStream> {
        let fields = match fields {
            Fields::Unit => {
                return Ok(quote!(write!(
                    _derive_more_Display_formatter,
                    stringify!(#name)
                )));
            }
            Fields::Named(fields) => &fields.named,
            Fields::Unnamed(fields) => &fields.unnamed,
        };
        if fields.len() == 0 {
            return Ok(quote!(write!(
                _derive_more_Display_formatter,
                stringify!(#name)
            )));
        } else if fields.len() > 1 {
            return Err(Error::new(
                fields.span(),
                "Can not automatically infer format for types with more than 1 field",
            ));
        }

        let trait_path = self.trait_path;
        if let Some(ident) = &fields.iter().next().as_ref().unwrap().ident {
            Ok(quote!(#trait_path::fmt(#ident, _derive_more_Display_formatter)))
        } else {
            Ok(quote!(#trait_path::fmt(_0, _derive_more_Display_formatter)))
        }
    }
    fn get_match_arms(&self) -> Result<TokenStream> {
        match &self.input.data {
            Data::Enum(e) => {
                if let Some(meta) = self.find_meta(&self.input.attrs)? {
                    let fmt = self.get_meta_fmt(meta)?;
                    e.variants.iter().try_for_each(|v| {
                        if let Some(meta) = self.find_meta(&v.attrs)? {
                            Err(Error::new(
                                meta.span(),
                                "Can not have a format on the variant when the whole enum has one",
                            ))
                        } else {
                            Ok(())
                        }
                    })?;
                    Ok(quote_spanned!(self.input.span()=> _ => #fmt,))
                } else {
                    e.variants.iter().try_fold(TokenStream::new(), |arms, v| {
                        let matcher = self.get_matcher(&v.fields);
                        let fmt = if let Some(meta) = self.find_meta(&v.attrs)? {
                            self.get_meta_fmt(meta)?
                        } else {
                            self.infer_fmt(&v.fields, &v.ident)?
                        };
                        let name = &self.input.ident;
                        let v_name = &v.ident;
                        Ok(quote_spanned!(self.input.span()=> #arms #name::#v_name #matcher => #fmt,))
                    })
                }
            }
            Data::Struct(s) => {
                let matcher = self.get_matcher(&s.fields);
                let fmt = if let Some(meta) = self.find_meta(&self.input.attrs)? {
                    self.get_meta_fmt(meta)?
                } else {
                    self.infer_fmt(&s.fields, &self.input.ident)?
                };
                let name = &self.input.ident;
                Ok(quote_spanned!(self.input.span()=> #name #matcher => #fmt,))
            }
            Data::Union(_) => {
                let meta = self.find_meta(&self.input.attrs)?.ok_or(Error::new(
                    self.input.span(),
                    "Can not automatically infer format for unions",
                ))?;
                let fmt = self.get_meta_fmt(meta)?;
                Ok(quote_spanned!(self.input.span()=> _ => #fmt,))
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::{BuildMetadata, Prerelease, Version};
use std::fmt::{self, Debug, Display};

impl Display for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.major, formatter)?;
        formatter.write_str(".")?;
        Display::fmt(&self.minor, formatter)?;
        formatter.write_str(".")?;
        Display::fmt(&self.patch, formatter)?;
        if !self.pre.is_empty() {
            formatter.write_str("-")?;
            Display::fmt(&self.pre, formatter)?;
        }
        if !self.build.is_empty() {
            formatter.write_str("+")?;
            Display::fmt(&self.build, formatter)?;
        }
        Ok(())
    }
}

impl Display for Prerelease {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.as_str())
    }
}

impl Display for BuildMetadata {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.as_str())
    }
}

impl Debug for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let mut debug = formatter.debug_struct("Version");
        debug
            .field("major", &self.major)
            .field("minor", &self.minor)
            .field("patch", &self.patch);
        if !self.pre.is_empty() {
            debug.field("pre", &self.pre);
        }
        if !self.build.is_empty() {
            debug.field("build", &self.build);
        }
        debug.finish()
    }
}

impl Debug for Prerelease {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Prerelease(\"")?;
        Display::fmt(self, formatter)?;
        formatter.write_str("\")")?;
        Ok(())
    }
}

impl Debug for BuildMetadata {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("BuildMetadata(\"")?;
        Display::fmt(self, formatter)?;
        formatter.write_str("\")")?;
        Ok(())
    }
}
<commit_msg>Display for Comparator<commit_after>use crate::{BuildMetadata, Comparator, Op, Prerelease, Version};
use std::fmt::{self, Debug, Display};

impl Display for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.major, formatter)?;
        formatter.write_str(".")?;
        Display::fmt(&self.minor, formatter)?;
        formatter.write_str(".")?;
        Display::fmt(&self.patch, formatter)?;
        if !self.pre.is_empty() {
            formatter.write_str("-")?;
            Display::fmt(&self.pre, formatter)?;
        }
        if !self.build.is_empty() {
            formatter.write_str("+")?;
            Display::fmt(&self.build, formatter)?;
        }
        Ok(())
    }
}

impl Display for Comparator {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let op = match self.op {
            Op::Exact => "=",
            Op::Greater => ">",
            Op::GreaterEq => ">=",
            Op::Less => "<",
            Op::LessEq => "<=",
            Op::Tilde => "~",
            Op::Caret => "^",
            Op::Wildcard => "",
        };
        formatter.write_str(op)?;
        Display::fmt(&self.major, formatter)?;
        if let Some(minor) = &self.minor {
            formatter.write_str(".")?;
            Display::fmt(minor, formatter)?;
            if let Some(patch) = &self.patch {
                formatter.write_str(".")?;
                Display::fmt(patch, formatter)?;
                if !self.pre.is_empty() {
                    formatter.write_str("-")?;
                    Display::fmt(&self.pre, formatter)?;
                }
            } else if self.op == Op::Wildcard {
                formatter.write_str(".*")?;
            }
        } else if self.op == Op::Wildcard {
            formatter.write_str(".*")?;
        }
        Ok(())
    }
}

impl Display for Prerelease {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.as_str())
    }
}

impl Display for BuildMetadata {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.as_str())
    }
}

impl Debug for Version {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let mut debug = formatter.debug_struct("Version");
        debug
            .field("major", &self.major)
            .field("minor", &self.minor)
            .field("patch", &self.patch);
        if !self.pre.is_empty() {
            debug.field("pre", &self.pre);
        }
        if !self.build.is_empty() {
            debug.field("build", &self.build);
        }
        debug.finish()
    }
}

impl Debug for Prerelease {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("Prerelease(\"")?;
        Display::fmt(self, formatter)?;
        formatter.write_str("\")")?;
        Ok(())
    }
}

impl Debug for BuildMetadata {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("BuildMetadata(\"")?;
        Display::fmt(self, formatter)?;
        formatter.write_str("\")")?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Structures that represent file-level features.

use Version;

const MAJOR: u8 = 1;

/// A trait implemented by each feature.
pub trait Feature {
    /// Is this feature supported by this version?
    ///
    /// # Examples
    ///
    /// ```
    /// use las::feature::{Waveforms, Feature};
    /// use las::Version;
    /// assert!(!Waveforms::is_supported_by(Version::new(1, 2)));
    /// assert!(Waveforms::is_supported_by(Version::new(1, 4)));
    /// ```
    fn is_supported_by(version: Version) -> bool;

    /// Returns the name of this feature.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::feature::{Waveforms, Feature};
    /// assert_eq!("Waveforms", Waveforms::name());
    /// ```
    fn name() -> &'static str;
}

macro_rules! feature {
    ($name:ident, $($versions:expr),+) => {
        #[derive(Clone, Copy, Debug)]
        #[allow(missing_docs)]
        pub struct $name {}

        impl Feature for $name {
            fn is_supported_by(version: Version) -> bool {
                vec![$($versions),+]
                    .into_iter()
                    .map(|minor| Version::new(MAJOR, minor))
                    .any(|v| version == v)
            }

            fn name() -> &'static str {
                stringify!($name)
            }
        }
    }
}

feature!(FileSourceId, 1, 2, 3, 4);
feature!(GpsStandardTime, 2, 3, 4);
feature!(Waveforms, 3, 4);
feature!(SyntheticReturnNumbers, 3, 4);
feature!(LargeFiles, 4);
feature!(Evlrs, 4);
<commit_msg>Improve feature.rs<commit_after>//! Programatically determine whether a las version supports a feature.
//!
//! Features are structures that implement the `Feature` trait. The most common way to use features
//! is via `Version::supports` or `Version::verify_support_for`:
//!
//! ```
//! use las::feature::Waveforms;
//! use las::{Version, Error};
//!
//! let las_1_2 = Version::new(1, 2);
//! assert!(!las_1_2.supports::<Waveforms>());
//! assert!(las_1_2.verify_support_for::<Waveforms>().is_err());
//!
//! let las_1_4 = Version::new(1, 4);
//! assert!(las_1_4.supports::<Waveforms>());
//! assert!(las_1_4.verify_support_for::<Waveforms>().is_ok());
//! ```

use Version;

const MAJOR: u8 = 1;

/// A trait implemented by each feature.
pub trait Feature {
    /// Is this feature supported by this version?
    ///
    /// # Examples
    ///
    /// ```
    /// use las::feature::{Waveforms, Feature};
    /// use las::Version;
    /// assert!(!Waveforms::is_supported_by(Version::new(1, 2)));
    /// assert!(Waveforms::is_supported_by(Version::new(1, 4)));
    /// ```
    fn is_supported_by(version: Version) -> bool;

    /// Returns the name of this feature.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::feature::{Waveforms, Feature};
    /// assert_eq!("Waveforms", Waveforms::name());
    /// ```
    fn name() -> &'static str;
}

macro_rules! features {
    (   $(
            $(#[$meta:meta])*
            $name:ident ($($versions:expr),+);
        )+
    ) => {
        $(
            $(#[$meta])*
            #[derive(Clone, Copy, Debug)]
            pub struct $name {}

            impl Feature for $name {
                fn is_supported_by(version: Version) -> bool {
                    vec![$($versions),+]
                        .into_iter()
                        .map(|minor| Version::new(MAJOR, minor))
                        .any(|v| version == v)
                }

                fn name() -> &'static str {
                    stringify!($name)
                }
            }
        )+
    }
}

features! {
    /// Does the header allow a file source id, or is that field reserved?
    FileSourceId(1, 2, 3, 4);
    /// Is there a bit flag to set the type of time value in each point?
    GpsStandardTime(2, 3, 4);
    /// Does this file support waveforms?
    Waveforms(3, 4);
    /// Is there a bit flag to indicate synthetic return numbers?
    SyntheticReturnNumbers(3, 4);
    /// Does this file support 64-bit point counts?
    LargeFiles(4);
    /// Does this file support extended variable length records?
    Evlrs(4);
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};

use img;
#[cfg(feature="openexr")]
use openexr::{FrameBufferMut, InputFile};

use {Point2i, clamp};
use bounds::Bounds2i;
use errors::*;
use fileutil::has_extension;
use spectrum::{Spectrum, gamma_correct};

pub fn read_image<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading image {}", path.as_ref().display());
    let path = path.as_ref();
    let extension = path.extension()
        .ok_or("Texture filename doesn't have an extension")?;
    if extension == "tga" || extension == "TGA" || extension == "png" || extension == "PNG" {
        read_image_tga_png(path)
    } else if extension == "exr" || extension == "EXR" {
        read_image_exr(path)
    } else if extension == "pfm" {
        read_image_pfm(path)
    } else {
        bail!("Unsupported file format");
    }
}

pub fn write_image<P: AsRef<Path>>(name: P, rgb: &[f32], output_bounds: &Bounds2i, total_resolution: &Point2i) -> Result<()> {
    let path = name.as_ref();
    let resolution = output_bounds.diagonal();

    if has_extension(path, "png") {
        let rgb8: Vec<_> = rgb.iter().map(|v| {
            clamp(255.0 * gamma_correct(*v) + 0.5, 0.0, 255.0) as u8
        }).collect();

        return img::save_buffer(path,
                         &rgb8,
                         resolution.x as u32,
                         resolution.y as u32,
                         img::RGB(8))
                .chain_err(|| format!("Failed to save image file {}", path.display()));
    } else {
        bail!("Unsupported file format");
    }
}

fn read_image_tga_png<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading texture {}", path.as_ref().display());
    let buf = img::open(path)?;

    let rgb = buf.to_rgb();
    let res = Point2i::new(rgb.width() as i32, rgb.height() as i32);
    let pixels: Vec<Spectrum> = rgb.pixels()
        .map(|p| {
                 let r = f32::from(p.data[0]) / 255.0;
                 let g = f32::from(p.data[1]) / 255.0;
                 let b = f32::from(p.data[2]) / 255.0;
                 Spectrum::rgb(r, g, b)
             })
        .collect();

    Ok((pixels, res))
}

#[cfg(not(feature="openexr"))]
fn read_image_exr<P: AsRef<Path>>(_path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    panic!("EXR support is not compiled in. Please recompile with the \"openexr\" feature.")
}

#[cfg(feature="openexr")]
fn read_image_exr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading EXR texture {}", path.as_ref().display());
    let mut file = File::open(path.as_ref())?;
    let mut exr_file = InputFile::new(&mut file).unwrap();
    let (width, height) = {
        let window = exr_file.header().data_window();
        let width = window.max.x - window.min.x + 1;
        let height = window.max.y - window.min.y + 1;
        (width, height)
    };

    let mut pixel_data: Vec<(f32, f32, f32)> = vec![(0.0, 0.0, 0.0); (width * height) as usize];

    {
        let mut fb = {
            // Create the frame buffer
            let mut fb = FrameBufferMut::new(width as usize, height as usize);
            fb.insert_channels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
            fb
        };

        exr_file.read_pixels(&mut fb).unwrap();
    }

    let pixels = pixel_data
        .iter()
        .map(|&(r, g, b)| Spectrum::rgb(r, g, b))
        .collect();
    Ok((pixels, Point2i::new(width, height)))
}

fn is_whitespace(c: char) -> bool {
    c == ' ' || c == '\n' || c == '\t'
}

fn read_word<R: BufRead>(f: &mut R) -> String {
    let mut buf = String::new();
    for c in f.bytes() {
        let c = c.unwrap() as char;
        if is_whitespace(c) {
            break;
        }
        buf.push(c);
    }

    buf
}

fn read_image_pfm<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading PFM file {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let mut reader = BufReader::new(file);
    let mut word;

    word = read_word(&mut reader);
    let n_channels = if &word == "Pf" {
        1
    } else if &word == "PF" {
        3
    } else {
        bail!("Error reading PFM file \"{}\"", path.as_ref().display());
    };

    // Read the rest of the header
    // Read width
    word = read_word(&mut reader);
    let width: usize = word.parse().chain_err(|| "Failed to parse width")?;

    // Read height
    word = read_word(&mut reader);
    let height: usize = word.parse().chain_err(|| "Failed to parse height")?;

    // Read scale
    word = read_word(&mut reader);
    let scale: f32 = word.parse().chain_err(|| "Failed to parse scale")?;
    let file_little_endian = scale < 0.0;
    let host_little_endian = true;

    info!("n_channels={}, width={}, height={}, scale={}",
          n_channels,
          width,
          height,
          scale);

    // Read the rest of the data
    let n_floats = n_channels * width * height;
    let mut data = Vec::new();
    data.resize(n_floats, 0.0f32);
    // Flip in Y, as P*M has the origin at the lower left.
    for y in (0..height).rev() {
        for x in 0..width {
            for idx in 0..n_channels {
                let mut buf = [0u8; 4]; // buffer to read a float
                reader.read_exact(&mut buf)?;
                if host_little_endian ^ file_little_endian {
                    buf.as_mut().swap(0, 3);
                    buf.as_mut().swap(1, 2);
                }
                let mut float = unsafe { ::std::mem::transmute::<[u8; 4], f32>(buf) };
                if scale.abs() != 1.0 {
                    float *= scale.abs();
                }
                data[y * n_channels * width + x * n_channels + idx] = float;
            }
        }
    }

    let rgb: Vec<Spectrum> = if n_channels == 1 {
        data.iter().map(|v| Spectrum::from(*v)).collect()
    } else {
        data.chunks(3)
            .map(|rgb| Spectrum::rgb(rgb[0], rgb[1], rgb[2]))
            .collect()
    };

    Ok((rgb, Point2i::new(width as i32, height as i32)))
}
<commit_msg>Add support for loading HDR files (thanks to Image)<commit_after>use std::path::Path;
use std::fs::File;
use std::io::{BufRead, BufReader, Read};

use img;
#[cfg(feature="openexr")]
use openexr::{FrameBufferMut, InputFile};

use {Point2i, clamp};
use bounds::Bounds2i;
use errors::*;
use fileutil::has_extension;
use spectrum::{Spectrum, gamma_correct};

pub fn read_image<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading image {}", path.as_ref().display());
    let path = path.as_ref();
    let extension = path.extension()
        .ok_or("Texture filename doesn't have an extension")?;
    if extension == "tga" || extension == "TGA" || extension == "png" || extension == "PNG" {
        read_image_tga_png(path)
    } else if extension == "exr" || extension == "EXR" {
        read_image_exr(path)
    } else if extension == "pfm" {
        read_image_pfm(path)
    } else if extension == "hdr" {
        read_image_hdr(path)
    } else {
        bail!("Unsupported file format");
    }
}

pub fn write_image<P: AsRef<Path>>(name: P, rgb: &[f32], output_bounds: &Bounds2i, total_resolution: &Point2i) -> Result<()> {
    let path = name.as_ref();
    let resolution = output_bounds.diagonal();

    if has_extension(path, "png") {
        let rgb8: Vec<_> = rgb.iter().map(|v| {
            clamp(255.0 * gamma_correct(*v) + 0.5, 0.0, 255.0) as u8
        }).collect();

        return img::save_buffer(path,
                         &rgb8,
                         resolution.x as u32,
                         resolution.y as u32,
                         img::RGB(8))
                .chain_err(|| format!("Failed to save image file {}", path.display()));
    } else {
        bail!("Unsupported file format");
    }
}

fn read_image_tga_png<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading texture {}", path.as_ref().display());
    let buf = img::open(path)?;

    let rgb = buf.to_rgb();
    let res = Point2i::new(rgb.width() as i32, rgb.height() as i32);
    let pixels: Vec<Spectrum> = rgb.pixels()
        .map(|p| {
                 let r = f32::from(p.data[0]) / 255.0;
                 let g = f32::from(p.data[1]) / 255.0;
                 let b = f32::from(p.data[2]) / 255.0;
                 Spectrum::rgb(r, g, b)
             })
        .collect();

    Ok((pixels, res))
}

fn read_image_hdr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading HDR image {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let reader = BufReader::new(file);
    let hdr = img::hdr::HDRDecoder::new(reader)?;

    let meta = hdr.metadata();
    let data = hdr.read_image_transform(|p| {
        let rgb = p.to_hdr();
        Spectrum::rgb(rgb[0], rgb[1], rgb[2])
    })?;

    Ok((data, Point2i::new(meta.width as i32, meta.height as i32)))
}

#[cfg(not(feature="openexr"))]
fn read_image_exr<P: AsRef<Path>>(_path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    panic!("EXR support is not compiled in. Please recompile with the \"openexr\" feature.")
}

#[cfg(feature="openexr")]
fn read_image_exr<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading EXR texture {}", path.as_ref().display());
    let mut file = File::open(path.as_ref())?;
    let mut exr_file = InputFile::new(&mut file).unwrap();
    let (width, height) = {
        let window = exr_file.header().data_window();
        let width = window.max.x - window.min.x + 1;
        let height = window.max.y - window.min.y + 1;
        (width, height)
    };

    let mut pixel_data: Vec<(f32, f32, f32)> = vec![(0.0, 0.0, 0.0); (width * height) as usize];

    {
        let mut fb = {
            // Create the frame buffer
            let mut fb = FrameBufferMut::new(width as usize, height as usize);
            fb.insert_channels(&[("R", 0.0), ("G", 0.0), ("B", 0.0)], &mut pixel_data);
            fb
        };

        exr_file.read_pixels(&mut fb).unwrap();
    }

    let pixels = pixel_data
        .iter()
        .map(|&(r, g, b)| Spectrum::rgb(r, g, b))
        .collect();
    Ok((pixels, Point2i::new(width, height)))
}

fn is_whitespace(c: char) -> bool {
    c == ' ' || c == '\n' || c == '\t'
}

fn read_word<R: BufRead>(f: &mut R) -> String {
    let mut buf = String::new();
    for c in f.bytes() {
        let c = c.unwrap() as char;
        if is_whitespace(c) {
            break;
        }
        buf.push(c);
    }

    buf
}

fn read_image_pfm<P: AsRef<Path>>(path: P) -> Result<(Vec<Spectrum>, Point2i)> {
    info!("Loading PFM file {}", path.as_ref().display());
    let file = File::open(path.as_ref())?;
    let mut reader = BufReader::new(file);
    let mut word;

    word = read_word(&mut reader);
    let n_channels = if &word == "Pf" {
        1
    } else if &word == "PF" {
        3
    } else {
        bail!("Error reading PFM file \"{}\"", path.as_ref().display());
    };

    // Read the rest of the header
    // Read width
    word = read_word(&mut reader);
    let width: usize = word.parse().chain_err(|| "Failed to parse width")?;

    // Read height
    word = read_word(&mut reader);
    let height: usize = word.parse().chain_err(|| "Failed to parse height")?;

    // Read scale
    word = read_word(&mut reader);
    let scale: f32 = word.parse().chain_err(|| "Failed to parse scale")?;
    let file_little_endian = scale < 0.0;
    let host_little_endian = true;

    info!("n_channels={}, width={}, height={}, scale={}",
          n_channels,
          width,
          height,
          scale);

    // Read the rest of the data
    let n_floats = n_channels * width * height;
    let mut data = Vec::new();
    data.resize(n_floats, 0.0f32);
    // Flip in Y, as P*M has the origin at the lower left.
    for y in (0..height).rev() {
        for x in 0..width {
            for idx in 0..n_channels {
                let mut buf = [0u8; 4]; // buffer to read a float
                reader.read_exact(&mut buf)?;
                if host_little_endian ^ file_little_endian {
                    buf.as_mut().swap(0, 3);
                    buf.as_mut().swap(1, 2);
                }
                let mut float = unsafe { ::std::mem::transmute::<[u8; 4], f32>(buf) };
                if scale.abs() != 1.0 {
                    float *= scale.abs();
                }
                data[y * n_channels * width + x * n_channels + idx] = float;
            }
        }
    }

    let rgb: Vec<Spectrum> = if n_channels == 1 {
        data.iter().map(|v| Spectrum::from(*v)).collect()
    } else {
        data.chunks(3)
            .map(|rgb| Spectrum::rgb(rgb[0], rgb[1], rgb[2]))
            .collect()
    };

    Ok((rgb, Point2i::new(width as i32, height as i32)))
}
<|endoftext|>


<commit_before>use js::value::{Value, VNumber, VInteger, VFunction, VObject, ResultValue};
use js::function::{NativeFunction, NativeFunc};
use js::object::ObjectData;
use collections::treemap::TreeMap;
use rand::random;
use std::io::stdio;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;

/// Get the absolute value of a number
pub fn abs(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().abs()
	} else {
		f64::NAN
	})))
}
/// Get the arccos of a number
pub fn acos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().acos()
	} else {
		f64::NAN
	})))
}
/// Get the arcsine of a number
pub fn asin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().asin()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a number
pub fn atan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a numbers
pub fn atan2(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan2(&args.get(1).borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Get the cubic root of a number
pub fn cbrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cbrt()
	} else {
		f64::NAN
	})))
}
/// Get lowest integer above a number
pub fn ceil(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().ceil()
	} else {
		f64::NAN
	})))
}
/// Get the cosine of a number
pub fn cos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cos()
	} else {
		f64::NAN
	})))
}
/// Get the power to raise the natural logarithm to get the number
pub fn exp(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().exp()
	} else {
		f64::NAN
	})))
}
/// Get the highest integer below a number
pub fn floor(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().floor()
	} else {
		f64::NAN
	})))
}
/// Get the natural logarithm of a number
pub fn log(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().log(&f64::consts::E)
	} else {
		f64::NAN
	})))
}
/// Get the maximum of several numbers
pub fn max(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::NEG_INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.max(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Get the minimum of several numbers
pub fn min(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.min(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Generate a random floating-point number between 0 and 1
pub fn _random(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(random())))
}
/// Get the sine of a number
pub fn sin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sin()
	} else {
		f64::NAN
	})))
}
/// Get the tangent of a number
pub fn tan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().tan()
	} else {
		f64::NAN
	})))
}
/// Create a new 'Math' object
pub fn _create() -> Value {
	let mut math = TreeMap::new();
	math.insert(~"E", Gc::new(VNumber(f64::consts::E)));
	math.insert(~"LN2", Gc::new(VNumber(f64::consts::LN_2)));
	math.insert(~"LN10", Gc::new(VNumber(f64::consts::LN_10)));
	math.insert(~"LOG2E", Gc::new(VNumber(f64::consts::LOG2_E)));
	math.insert(~"LOG10E", Gc::new(VNumber(f64::consts::LOG10_E)));
	math.insert(~"SQRT1_2", Gc::new(VNumber(0.5f64.sqrt())));
	math.insert(~"SQRT2", Gc::new(VNumber(f64::consts::SQRT2)));
	math.insert(~"PI", Gc::new(VNumber(f64::consts::PI)));
	math.insert(~"abs", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(abs, 1))))));
	math.insert(~"acos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(acos, 1))))));
	math.insert(~"asin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(asin, 1))))));
	math.insert(~"atan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan, 1))))));
	math.insert(~"atan2", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan2, 2))))));
	math.insert(~"cbrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cbrt, 1))))));
	math.insert(~"ceil", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(ceil, 1))))));
	math.insert(~"cos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cos, 1))))));
	math.insert(~"exp", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(exp, 1))))));
	math.insert(~"floor", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(floor, 1))))));
	math.insert(~"log", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(log, 1))))));
	math.insert(~"max", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(max, 2))))));
	math.insert(~"min", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(min, 2))))));
	math.insert(~"random", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(_random, 0))))));
	math.insert(~"sin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sin, 1))))));
	math.insert(~"tan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(tan, 1))))));
	Gc::new(VObject(RefCell::new(math)))
}<commit_msg>Add Math.pow(num, radix)<commit_after>use js::value::{Value, VNumber, VInteger, VFunction, VObject, ResultValue};
use js::function::{NativeFunction, NativeFunc};
use js::object::ObjectData;
use collections::treemap::TreeMap;
use rand::random;
use std::io::stdio;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;

/// Get the absolute value of a number
pub fn abs(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().abs()
	} else {
		f64::NAN
	})))
}
/// Get the arccos of a number
pub fn acos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().acos()
	} else {
		f64::NAN
	})))
}
/// Get the arcsine of a number
pub fn asin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().asin()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a number
pub fn atan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a numbers
pub fn atan2(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan2(&args.get(1).borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Get the cubic root of a number
pub fn cbrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cbrt()
	} else {
		f64::NAN
	})))
}
/// Get lowest integer above a number
pub fn ceil(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().ceil()
	} else {
		f64::NAN
	})))
}
/// Get the cosine of a number
pub fn cos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cos()
	} else {
		f64::NAN
	})))
}
/// Get the power to raise the natural logarithm to get the number
pub fn exp(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().exp()
	} else {
		f64::NAN
	})))
}
/// Get the highest integer below a number
pub fn floor(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().floor()
	} else {
		f64::NAN
	})))
}
/// Get the natural logarithm of a number
pub fn log(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().log(&f64::consts::E)
	} else {
		f64::NAN
	})))
}
/// Get the maximum of several numbers
pub fn max(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::NEG_INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.max(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Get the minimum of several numbers
pub fn min(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.min(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Raise a number to a power
pub fn pow(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 2 {
		let num = args.get(0);
		let power = args.get(1);
		num.borrow().to_num().powf(&power.borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Generate a random floating-point number between 0 and 1
pub fn _random(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(random())))
}
/// Get the sine of a number
pub fn sin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sin()
	} else {
		f64::NAN
	})))
}
/// Get the tangent of a number
pub fn tan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().tan()
	} else {
		f64::NAN
	})))
}
/// Create a new 'Math' object
pub fn _create() -> Value {
	let mut math = TreeMap::new();
	math.insert(~"E", Gc::new(VNumber(f64::consts::E)));
	math.insert(~"LN2", Gc::new(VNumber(f64::consts::LN_2)));
	math.insert(~"LN10", Gc::new(VNumber(f64::consts::LN_10)));
	math.insert(~"LOG2E", Gc::new(VNumber(f64::consts::LOG2_E)));
	math.insert(~"LOG10E", Gc::new(VNumber(f64::consts::LOG10_E)));
	math.insert(~"SQRT1_2", Gc::new(VNumber(0.5f64.sqrt())));
	math.insert(~"SQRT2", Gc::new(VNumber(f64::consts::SQRT2)));
	math.insert(~"PI", Gc::new(VNumber(f64::consts::PI)));
	math.insert(~"abs", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(abs, 1))))));
	math.insert(~"acos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(acos, 1))))));
	math.insert(~"asin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(asin, 1))))));
	math.insert(~"atan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan, 1))))));
	math.insert(~"atan2", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan2, 2))))));
	math.insert(~"cbrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cbrt, 1))))));
	math.insert(~"ceil", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(ceil, 1))))));
	math.insert(~"cos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cos, 1))))));
	math.insert(~"exp", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(exp, 1))))));
	math.insert(~"floor", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(floor, 1))))));
	math.insert(~"log", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(log, 1))))));
	math.insert(~"max", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(max, 2))))));
	math.insert(~"min", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(min, 2))))));
	math.insert(~"pow", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(pow, 2))))));
	math.insert(~"random", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(_random, 0))))));
	math.insert(~"sin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sin, 1))))));
	math.insert(~"tan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(tan, 1))))));
	Gc::new(VObject(RefCell::new(math)))
}<|endoftext|>


<commit_before>use term::{self, Terminal, TerminfoTerminal};
use term::terminfo::TermInfo;
use fern;
use log::{LogLevel, LogLevelFilter};
use std::io::{self, Write};
use chrono;

use xivdb::error::*;

lazy_static! {
  static ref TERM_INFO: Option<TermInfo> = TermInfo::from_env().ok();
}

fn colored_level(level: LogLevel) -> String {
  let mut t = match *TERM_INFO {
    Some(ref t) => TerminfoTerminal::new_with_terminfo(vec![0u8, 0], t.clone()),
    None => return format!("{}", level)
  };
  let color = match level {
    LogLevel::Trace => term::color::BRIGHT_BLACK,
    LogLevel::Info => term::color::BLUE,
    LogLevel::Warn => term::color::YELLOW,
    LogLevel::Error => term::color::RED,
    _ => return format!("{}", level)
  };
  t.fg(color).unwrap();
  write!(t, "{}", level).unwrap();
  t.reset().unwrap();
  String::from_utf8_lossy(&t.into_inner()).to_string()
}

fn colored_target(target: &str) -> String {
  let parts: Vec<&str> = target.split("::").collect();
  if parts.len() == 1 {
    return target.to_string();
  }
  let base = &parts[..parts.len() - 1];
  let target = &parts[parts.len() - 1];
  let mut t = match *TERM_INFO {
    Some(ref t) => TerminfoTerminal::new_with_terminfo(vec![0u8, 0], t.clone()),
    None => return target.to_string()
  };
  for part in base {
    write!(t, "{}", part).unwrap();
    t.fg(term::color::BRIGHT_BLACK).unwrap();
    write!(t, "::").unwrap();
    t.reset().unwrap();
  }
  write!(t, "{}", target).unwrap();
  String::from_utf8_lossy(&t.into_inner()).to_string()
}

pub fn init_logger() -> Result<()> {
  fern::Dispatch::new()
    .format(|out, message, record| {
      out.finish(format_args!("[{}] [{}] {} – {}",
        chrono::Local::now().format("%H:%M:%S"),
        colored_level(record.level()),
        colored_target(record.target()),
        message))
    })
    .level(LogLevelFilter::Info)
    .chain(io::stdout())
    .apply()
    .chain_err(|| "could not set up logger")
}
<commit_msg>fix: don't initialize with two empty bytes<commit_after>use term::{self, Terminal, TerminfoTerminal};
use term::terminfo::TermInfo;
use fern;
use log::{LogLevel, LogLevelFilter};
use std::io::{self, Write};
use chrono;

use xivdb::error::*;

lazy_static! {
  static ref TERM_INFO: Option<TermInfo> = TermInfo::from_env().ok();
}

fn colored_level(level: LogLevel) -> String {
  let mut t = match *TERM_INFO {
    Some(ref t) => TerminfoTerminal::new_with_terminfo(vec![0u8; 0], t.clone()),
    None => return format!("{}", level)
  };
  let color = match level {
    LogLevel::Trace => term::color::BRIGHT_BLACK,
    LogLevel::Info => term::color::BLUE,
    LogLevel::Warn => term::color::YELLOW,
    LogLevel::Error => term::color::RED,
    _ => return format!("{}", level)
  };
  t.fg(color).unwrap();
  write!(t, "{}", level).unwrap();
  t.reset().unwrap();
  String::from_utf8_lossy(&t.into_inner()).to_string()
}

fn colored_target(target: &str) -> String {
  let parts: Vec<&str> = target.split("::").collect();
  if parts.len() == 1 {
    return target.to_string();
  }
  let base = &parts[..parts.len() - 1];
  let target = &parts[parts.len() - 1];
  let mut t = match *TERM_INFO {
    Some(ref t) => TerminfoTerminal::new_with_terminfo(vec![0u8; 0], t.clone()),
    None => return target.to_string()
  };
  for part in base {
    write!(t, "{}", part).unwrap();
    t.fg(term::color::BRIGHT_BLACK).unwrap();
    write!(t, "::").unwrap();
    t.reset().unwrap();
  }
  write!(t, "{}", target).unwrap();
  String::from_utf8_lossy(&t.into_inner()).to_string()
}

pub fn init_logger() -> Result<()> {
  fern::Dispatch::new()
    .format(|out, message, record| {
      out.finish(format_args!("[{}] [{}] {} – {}",
        chrono::Local::now().format("%H:%M:%S"),
        colored_level(record.level()),
        colored_target(record.target()),
        message))
    })
    .level(LogLevelFilter::Info)
    .chain(io::stdout())
    .apply()
    .chain_err(|| "could not set up logger")
}
<|endoftext|>


<commit_before>//! Traits, implementations, and macros related to logging timely events.

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;
use std::rc::Rc;

use ::Data;

use timely_communication::Allocate;
use timely_communication;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;
use ::progress::timestamp::Timestamp;

use byteorder::{LittleEndian, WriteBytesExt};

use dataflow::scopes::root::Root;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

use std::io::BufWriter;
use std::net::TcpStream;

use timely_logging;
use timely_logging::Event as LogEvent;
use timely_logging::EventsSetup;
use timely_logging::{CommEvent, CommsSetup};

use timely_communication::Logging;

pub use timely_logging::OperatesEvent;
pub use timely_logging::ChannelsEvent;
pub use timely_logging::ProgressEvent;
pub use timely_logging::MessagesEvent;
pub use timely_logging::ScheduleEvent;
pub use timely_logging::StartStop;
pub use timely_logging::PushProgressEvent;
pub use timely_logging::ApplicationEvent;
pub use timely_logging::GuardedProgressEvent;
pub use timely_logging::GuardedMessageEvent;
pub use timely_logging::CommChannelsEvent;

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: ::timely_logging::Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// TODO(andreal)
pub struct TimelyLogger<V: Abomonation> where LogEvent: From<V> {
    stream: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>>,
    _v: ::std::marker::PhantomData<V>,
}

impl<V: Abomonation> TimelyLogger<V> where LogEvent: From<V> {
    fn new(stream: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>>) -> TimelyLogger<V> {
        TimelyLogger {
            stream: stream,
            _v: ::std::marker::PhantomData,
        }
    }
}

impl<V: Abomonation> ::timely_logging::Logger for TimelyLogger<V> where timely_logging::Event: From<V> {
    type Record = V;
    fn log(&self, record: V) {
        self.stream.borrow_mut().log(LogEvent::from(record));
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {
    eprintln!("logging: index {}/{}", root.index(), root.peers());
    LOG_EVENT_STREAM.with(|x| {
        x.borrow_mut().setup = Some(EventsSetup {
            index: root.index(),
        });
    });
}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    LOG_EVENT_STREAM.with(|x| {
        x.borrow_mut().flush();
    });
}

// trait ScheduleLogger {
//     fn contains_active_ops(&self) -> bool;
// }
//
// impl<S: Write> ScheduleLogger for LogEventStream<ScheduleEvent, S> {
//     fn contains_active_ops(&self) -> bool {
//         self.buffer.borrow().iter().any(|&(ref evt, ts) | {
//             match evt.start_stop {
//                 StartStop::Stop { activity } => activity,
//                 _ => false,
//             }
//         })
//     }
// }

struct LogEventStream<S: Copy, E: Clone> {
    setup: Option<S>,
    writer: Option<Box<EventStreamInput<Product<RootTimestamp, u64>, (u64, S, E)>>>,
    _s: ::std::marker::PhantomData<S>,
    _e: ::std::marker::PhantomData<E>,
}

impl<S: Copy, E: Clone> LogEventStream<S, E> {
    fn new() -> Self {
        LogEventStream {
            setup: None,
            writer: None,
            _s: ::std::marker::PhantomData,
            _e: ::std::marker::PhantomData,
        }
    }

    fn flush(&mut self) {
        if let Some(ref mut writer) = self.writer {
            writer.advance_by(RootTimestamp::new(::timely_logging::get_precise_time_ns()));
        }
    }

    fn log(&mut self, record: E) {
        if let Some(ref mut writer) = self.writer {
            writer.send(
                (::timely_logging::get_precise_time_ns(), self.setup.expect("logging not initialized"), record));
        }
    }
}

trait EventStreamInput<T: Timestamp, V: Clone> {
    fn send(&mut self, value: V);
    fn flush(&mut self);
    fn advance_by(&mut self, timestamp: T);
    fn clear(&mut self);
}

/// Logs events to an underlying writer.
pub struct EventStreamWriter<T: Timestamp, V: Clone, P: EventPusher<T, V>> {
    buffer: Vec<V>,
    pusher: P, // RefCell<Option<Box<EventPusher<Product<RootTimestamp, u64>, (u64, S, E)>+Send>>>,
    cur_time: T,
    _v: ::std::marker::PhantomData<V>,
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> EventStreamWriter<T, V, P> {
    fn new(mut event_pusher: P) -> EventStreamWriter<T, V, P> {
        let cur_time: T = Default::default();
        event_pusher.push(Event::Progress(vec![(cur_time.clone(), 1)]));
        EventStreamWriter {
            buffer: Vec::new(),
            pusher: event_pusher,
            cur_time: cur_time,
            _v: ::std::marker::PhantomData,
        }
    }
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> EventStreamInput<T, V> for EventStreamWriter<T, V, P> {
    fn send(&mut self, value: V) {
        self.buffer.push(value);
    }
    fn flush(&mut self) {
        if self.buffer.len() > 0 {
            self.pusher.push(Event::Messages(self.cur_time.clone(), self.buffer.clone()));
        }
        self.buffer.clear();
    }
    fn advance_by(&mut self, timestamp: T) {
        assert!(self.cur_time.less_equal(&timestamp));
        self.flush();
        self.pusher.push(Event::Progress(vec![(self.cur_time.clone(), -1), (timestamp.clone(), 1)]));
        self.cur_time = timestamp;
    }
    fn clear(&mut self) {
        self.buffer.clear();
    }
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> Drop for EventStreamWriter<T, V, P> {
    fn drop(&mut self) {
        if self.buffer.len() > 0 {
            self.pusher.push(Event::Messages(self.cur_time.clone(), self.buffer.clone()));
            self.buffer.clear();
        }
        self.pusher.push(Event::Progress(vec![(self.cur_time.clone(), -1)]));
    }
}

// /// Special logger for ScheduleEvents
// pub struct ScheduleLogEventStream<S: Write> {
//     logger: LogEventStream<ScheduleEvent, S>,
//     seen_inactive_step: RefCell<bool>,
// }
//
// impl<S: Write> ScheduleLogEventStream<S> {
//     fn new() -> ScheduleLogEventStream<S> {
//         ScheduleLogEventStream {
//             logger: LogEventStream::new(),
//             seen_inactive_step: RefCell::new(false),
//         }
//     }
//
//     fn set(&self, stream: S) {
//         self.logger.set(stream)
//     }
//
//     fn flush_forced(&self) {
//         self.flush();
//         *self.seen_inactive_step.borrow_mut() = false;
//     }
//
//     fn flush_maybe(&self) {
//         if self.logger.contains_active_ops() {
//             self.flush_forced();
//             return;
//         }
//         if !*self.seen_inactive_step.borrow() {
//             self.flush_forced();
//             *self.seen_inactive_step.borrow_mut() = true
//         } else {
//             self.logger.clear();
//         }
//
//     }
// }
//
// impl<S: Write> Logger for ScheduleLogEventStream<S> {
//     type Record = ScheduleEvent;
//     fn log(&self, record: Self::Record) {
//         self.logger.log(record)
//     }
//     fn flush(&self) {
//         self.logger.flush()
//     }
//     // fn record_count(&self) -> usize {
//     //     self.logger.record_count()
//     // }
//     // fn clear(&self) {
//     //     self.logger.clear()
//     // }
//
// }

/// TODO(andreal)
pub fn blackhole() -> Logging {
    Logging::new(
        None,
        Box::new(move || {
            LOG_EVENT_STREAM.with(|x| {
                x.borrow_mut().writer = None;
            });
        }))
}

/// TODO(andreal)
pub fn to_tcp_socket() -> Logging {
    ::timely_logging::initialize_precise_time_ns();
    let target: String = ::std::env::var("TIMELY_LOG_TARGET").expect("no $TIMELY_LOG_TARGET, e.g. 127.0.0.1:34254");
    let comm_target = ::std::env::var("TIMELY_COMM_LOG_TARGET").expect("no $TIMELY_COMM_LOG_TARGET, e.g. 127.0.0.1:34254");
    let (comms_snd, comms_rcv) = ::std::sync::mpsc::channel();

    // comms
    let comm_writer = BufWriter::with_capacity(4096,
        TcpStream::connect(comm_target).expect("failed to connect to logging destination"));
    /* thread is detached */ ::std::thread::spawn(move || {
        let mut writer = EventStreamWriter::new(EventWriter::new(comm_writer));
        let mut cur_time = timely_logging::get_precise_time_ns();
        writer.advance_by(RootTimestamp::new(cur_time));

        let mut receiver = comms_rcv;
        loop {
            let mut new_time = timely_logging::get_precise_time_ns();
            while let Some((ts, setup, event)) = match receiver.try_recv() {
                Ok(msg) => {
                    Some(msg)
                },
                Err(::std::sync::mpsc::TryRecvError::Empty) => None,
                Err(::std::sync::mpsc::TryRecvError::Disconnected) => return,
            } {
                writer.send((ts, setup, event));
            }
            writer.flush();
            writer.advance_by(RootTimestamp::new(new_time));
            cur_time = new_time;
        }
    });

    Logging::new(
        Some(comms_snd),
        Box::new(move || {
            // timely
            let socket = BufWriter::with_capacity(4096,
                TcpStream::connect(&target).expect("failed to connect to logging destination"));
            let mut timely_writer = EventStreamWriter::new(EventWriter::new(socket));
            timely_writer.advance_by(RootTimestamp::new(timely_logging::get_precise_time_ns()));
            LOG_EVENT_STREAM.with(|x| {
                x.borrow_mut().writer = Some(Box::new(timely_writer));
            });
        }))
}

thread_local!{
    /// TODO(andreal)
    static LOG_EVENT_STREAM: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>> = Rc::new(RefCell::new(LogEventStream::new()));
    /// TODO(andreal)
    /// Logs operator creation.
    pub static OPERATES: TimelyLogger<OperatesEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs channel creation.
    pub static CHANNELS: TimelyLogger<ChannelsEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs progress transmission.
    pub static PROGRESS: TimelyLogger<ProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs message transmission.
    pub static MESSAGES: TimelyLogger<MessagesEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs operator scheduling.
    pub static SCHEDULE: TimelyLogger<ScheduleEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs delivery of message to an operator input.
    pub static GUARDED_MESSAGE: TimelyLogger<GuardedMessageEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs delivery of notification to an operator.
    pub static GUARDED_PROGRESS: TimelyLogger<GuardedProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs push_external_progress() calls for each operator
    pub static PUSH_PROGRESS: TimelyLogger<PushProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs application-defined log events
    pub static APPLICATION: TimelyLogger<ApplicationEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs application-defined log events
    pub static COMM_CHANNELS: TimelyLogger<CommChannelsEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
}
<commit_msg>captured streams has implicit default cap<commit_after>//! Traits, implementations, and macros related to logging timely events.

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;
use std::rc::Rc;

use ::Data;

use timely_communication::Allocate;
use timely_communication;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;
use ::progress::timestamp::Timestamp;

use byteorder::{LittleEndian, WriteBytesExt};

use dataflow::scopes::root::Root;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

use std::io::BufWriter;
use std::net::TcpStream;

use timely_logging;
use timely_logging::Event as LogEvent;
use timely_logging::EventsSetup;
use timely_logging::{CommEvent, CommsSetup};

use timely_communication::Logging;

pub use timely_logging::OperatesEvent;
pub use timely_logging::ChannelsEvent;
pub use timely_logging::ProgressEvent;
pub use timely_logging::MessagesEvent;
pub use timely_logging::ScheduleEvent;
pub use timely_logging::StartStop;
pub use timely_logging::PushProgressEvent;
pub use timely_logging::ApplicationEvent;
pub use timely_logging::GuardedProgressEvent;
pub use timely_logging::GuardedMessageEvent;
pub use timely_logging::CommChannelsEvent;

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: ::timely_logging::Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// TODO(andreal)
pub struct TimelyLogger<V: Abomonation> where LogEvent: From<V> {
    stream: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>>,
    _v: ::std::marker::PhantomData<V>,
}

impl<V: Abomonation> TimelyLogger<V> where LogEvent: From<V> {
    fn new(stream: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>>) -> TimelyLogger<V> {
        TimelyLogger {
            stream: stream,
            _v: ::std::marker::PhantomData,
        }
    }
}

impl<V: Abomonation> ::timely_logging::Logger for TimelyLogger<V> where timely_logging::Event: From<V> {
    type Record = V;
    fn log(&self, record: V) {
        self.stream.borrow_mut().log(LogEvent::from(record));
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {
    eprintln!("logging: index {}/{}", root.index(), root.peers());
    LOG_EVENT_STREAM.with(|x| {
        x.borrow_mut().setup = Some(EventsSetup {
            index: root.index(),
        });
    });
}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    LOG_EVENT_STREAM.with(|x| {
        x.borrow_mut().flush();
    });
}

// trait ScheduleLogger {
//     fn contains_active_ops(&self) -> bool;
// }
//
// impl<S: Write> ScheduleLogger for LogEventStream<ScheduleEvent, S> {
//     fn contains_active_ops(&self) -> bool {
//         self.buffer.borrow().iter().any(|&(ref evt, ts) | {
//             match evt.start_stop {
//                 StartStop::Stop { activity } => activity,
//                 _ => false,
//             }
//         })
//     }
// }

struct LogEventStream<S: Copy, E: Clone> {
    setup: Option<S>,
    writer: Option<Box<EventStreamInput<Product<RootTimestamp, u64>, (u64, S, E)>>>,
    _s: ::std::marker::PhantomData<S>,
    _e: ::std::marker::PhantomData<E>,
}

impl<S: Copy, E: Clone> LogEventStream<S, E> {
    fn new() -> Self {
        LogEventStream {
            setup: None,
            writer: None,
            _s: ::std::marker::PhantomData,
            _e: ::std::marker::PhantomData,
        }
    }

    fn flush(&mut self) {
        if let Some(ref mut writer) = self.writer {
            writer.advance_by(RootTimestamp::new(::timely_logging::get_precise_time_ns()));
        }
    }

    fn log(&mut self, record: E) {
        if let Some(ref mut writer) = self.writer {
            writer.send(
                (::timely_logging::get_precise_time_ns(), self.setup.expect("logging not initialized"), record));
        }
    }
}

trait EventStreamInput<T: Timestamp, V: Clone> {
    fn send(&mut self, value: V);
    fn flush(&mut self);
    fn advance_by(&mut self, timestamp: T);
    fn clear(&mut self);
}

/// Logs events to an underlying writer.
pub struct EventStreamWriter<T: Timestamp, V: Clone, P: EventPusher<T, V>> {
    buffer: Vec<V>,
    pusher: P, // RefCell<Option<Box<EventPusher<Product<RootTimestamp, u64>, (u64, S, E)>+Send>>>,
    cur_time: T,
    _v: ::std::marker::PhantomData<V>,
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> EventStreamWriter<T, V, P> {
    fn new(mut event_pusher: P) -> EventStreamWriter<T, V, P> {
        let cur_time: T = Default::default();
        // event_pusher.push(Event::Progress(vec![(cur_time.clone(), 1)]));
        EventStreamWriter {
            buffer: Vec::new(),
            pusher: event_pusher,
            cur_time: cur_time,
            _v: ::std::marker::PhantomData,
        }
    }
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> EventStreamInput<T, V> for EventStreamWriter<T, V, P> {
    fn send(&mut self, value: V) {
        self.buffer.push(value);
    }
    fn flush(&mut self) {
        if self.buffer.len() > 0 {
            self.pusher.push(Event::Messages(self.cur_time.clone(), self.buffer.clone()));
        }
        self.buffer.clear();
    }
    fn advance_by(&mut self, timestamp: T) {
        assert!(self.cur_time.less_equal(&timestamp));
        self.flush();
        self.pusher.push(Event::Progress(vec![(self.cur_time.clone(), -1), (timestamp.clone(), 1)]));
        self.cur_time = timestamp;
    }
    fn clear(&mut self) {
        self.buffer.clear();
    }
}

impl<T: Timestamp, V: Clone, P: EventPusher<T, V>> Drop for EventStreamWriter<T, V, P> {
    fn drop(&mut self) {
        if self.buffer.len() > 0 {
            self.pusher.push(Event::Messages(self.cur_time.clone(), self.buffer.clone()));
            self.buffer.clear();
        }
        self.pusher.push(Event::Progress(vec![(self.cur_time.clone(), -1)]));
    }
}

// /// Special logger for ScheduleEvents
// pub struct ScheduleLogEventStream<S: Write> {
//     logger: LogEventStream<ScheduleEvent, S>,
//     seen_inactive_step: RefCell<bool>,
// }
//
// impl<S: Write> ScheduleLogEventStream<S> {
//     fn new() -> ScheduleLogEventStream<S> {
//         ScheduleLogEventStream {
//             logger: LogEventStream::new(),
//             seen_inactive_step: RefCell::new(false),
//         }
//     }
//
//     fn set(&self, stream: S) {
//         self.logger.set(stream)
//     }
//
//     fn flush_forced(&self) {
//         self.flush();
//         *self.seen_inactive_step.borrow_mut() = false;
//     }
//
//     fn flush_maybe(&self) {
//         if self.logger.contains_active_ops() {
//             self.flush_forced();
//             return;
//         }
//         if !*self.seen_inactive_step.borrow() {
//             self.flush_forced();
//             *self.seen_inactive_step.borrow_mut() = true
//         } else {
//             self.logger.clear();
//         }
//
//     }
// }
//
// impl<S: Write> Logger for ScheduleLogEventStream<S> {
//     type Record = ScheduleEvent;
//     fn log(&self, record: Self::Record) {
//         self.logger.log(record)
//     }
//     fn flush(&self) {
//         self.logger.flush()
//     }
//     // fn record_count(&self) -> usize {
//     //     self.logger.record_count()
//     // }
//     // fn clear(&self) {
//     //     self.logger.clear()
//     // }
//
// }

/// TODO(andreal)
pub fn blackhole() -> Logging {
    Logging::new(
        None,
        Box::new(move || {
            LOG_EVENT_STREAM.with(|x| {
                x.borrow_mut().writer = None;
            });
        }))
}

/// TODO(andreal)
pub fn to_tcp_socket() -> Logging {
    ::timely_logging::initialize_precise_time_ns();
    let target: String = ::std::env::var("TIMELY_LOG_TARGET").expect("no $TIMELY_LOG_TARGET, e.g. 127.0.0.1:34254");
    let comm_target = ::std::env::var("TIMELY_COMM_LOG_TARGET").expect("no $TIMELY_COMM_LOG_TARGET, e.g. 127.0.0.1:34254");
    let (comms_snd, comms_rcv) = ::std::sync::mpsc::channel();

    // comms
    let comm_writer = BufWriter::with_capacity(4096,
        TcpStream::connect(comm_target).expect("failed to connect to logging destination"));
    /* thread is detached */ ::std::thread::spawn(move || {
        let mut writer = EventStreamWriter::new(EventWriter::new(comm_writer));
        let mut cur_time = timely_logging::get_precise_time_ns();
        writer.advance_by(RootTimestamp::new(cur_time));

        let mut receiver = comms_rcv;
        loop {
            let mut new_time = timely_logging::get_precise_time_ns();
            while let Some((ts, setup, event)) = match receiver.try_recv() {
                Ok(msg) => {
                    Some(msg)
                },
                Err(::std::sync::mpsc::TryRecvError::Empty) => None,
                Err(::std::sync::mpsc::TryRecvError::Disconnected) => return,
            } {
                writer.send((ts, setup, event));
            }
            writer.flush();
            writer.advance_by(RootTimestamp::new(new_time));
            cur_time = new_time;
        }
    });

    Logging::new(
        Some(comms_snd),
        Box::new(move || {
            // timely
            let socket = BufWriter::with_capacity(4096,
                TcpStream::connect(&target).expect("failed to connect to logging destination"));
            let mut timely_writer = EventStreamWriter::new(EventWriter::new(socket));
            timely_writer.advance_by(RootTimestamp::new(timely_logging::get_precise_time_ns()));
            LOG_EVENT_STREAM.with(|x| {
                x.borrow_mut().writer = Some(Box::new(timely_writer));
            });
        }))
}

thread_local!{
    /// TODO(andreal)
    static LOG_EVENT_STREAM: Rc<RefCell<LogEventStream<EventsSetup, LogEvent>>> = Rc::new(RefCell::new(LogEventStream::new()));
    /// TODO(andreal)
    /// Logs operator creation.
    pub static OPERATES: TimelyLogger<OperatesEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs channel creation.
    pub static CHANNELS: TimelyLogger<ChannelsEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs progress transmission.
    pub static PROGRESS: TimelyLogger<ProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs message transmission.
    pub static MESSAGES: TimelyLogger<MessagesEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs operator scheduling.
    pub static SCHEDULE: TimelyLogger<ScheduleEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs delivery of message to an operator input.
    pub static GUARDED_MESSAGE: TimelyLogger<GuardedMessageEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs delivery of notification to an operator.
    pub static GUARDED_PROGRESS: TimelyLogger<GuardedProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs push_external_progress() calls for each operator
    pub static PUSH_PROGRESS: TimelyLogger<PushProgressEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs application-defined log events
    pub static APPLICATION: TimelyLogger<ApplicationEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
    /// Logs application-defined log events
    pub static COMM_CHANNELS: TimelyLogger<CommChannelsEvent> = LOG_EVENT_STREAM.with(|x| TimelyLogger::new(x.clone()));
}
<|endoftext|>


<commit_before>use if_chain::if_chain;
use rustc::hir::def::{DefKind, Res};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::ptr::P;

use crate::utils::paths::*;
use crate::utils::sugg::Sugg;
use crate::utils::{match_type, span_lint_and_then, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for expressions that could be replaced by the question mark operator.
    ///
    /// **Why is this bad?** Question mark usage is more idiomatic.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```ignore
    /// if option.is_none() {
    ///     return None;
    /// }
    /// ```
    ///
    /// Could be written:
    ///
    /// ```ignore
    /// option?;
    /// ```
    pub QUESTION_MARK,
    style,
    "checks for expressions that could be replaced by the question mark operator"
}

declare_lint_pass!(QuestionMark => [QUESTION_MARK]);

impl QuestionMark {
    /// Checks if the given expression on the given context matches the following structure:
    ///
    /// ```ignore
    /// if option.is_none() {
    ///    return None;
    /// }
    /// ```
    ///
    /// If it matches, it will suggest to use the question mark operator instead
    fn check_is_none_and_early_return_none(cx: &LateContext<'_, '_>, expr: &Expr) {
        if_chain! {
            if let ExprKind::If(if_expr, body, else_) = &expr.node;
            if let ExprKind::MethodCall(segment, _, args) = &if_expr.node;
            if segment.ident.name == "is_none";
            if Self::expression_returns_none(cx, body);
            if let Some(subject) = args.get(0);
            if Self::is_option(cx, subject);

            then {
                let receiver_str = &Sugg::hir(cx, subject, "..");
                let mut replacement: Option<String> = None;
                if let Some(else_) = else_ {
                    if_chain! {
                        if let ExprKind::Block(block, None) = &else_.node;
                        if block.stmts.len() == 0;
                        if let Some(block_expr) = &block.expr;
                        if SpanlessEq::new(cx).ignore_fn().eq_expr(subject, block_expr);
                        then {
                            replacement = Some(format!("Some({}?)", receiver_str));
                        }
                    }
                } else if Self::moves_by_default(cx, subject) {
                        replacement = Some(format!("{}.as_ref()?;", receiver_str));
                } else {
                        replacement = Some(format!("{}?;", receiver_str));
                }

                if let Some(replacement_str) = replacement {
                    span_lint_and_then(
                        cx,
                        QUESTION_MARK,
                        expr.span,
                        "this block may be rewritten with the `?` operator",
                        |db| {
                            db.span_suggestion(
                                expr.span,
                                "replace_it_with",
                                replacement_str,
                                Applicability::MaybeIncorrect, // snippet
                            );
                        }
                    )
               }
            }
        }
    }

    fn moves_by_default(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
        let expr_ty = cx.tables.expr_ty(expression);

        !expr_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, expression.span)
    }

    fn is_option(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
        let expr_ty = cx.tables.expr_ty(expression);

        match_type(cx, expr_ty, &OPTION)
    }

    fn expression_returns_none(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
        match expression.node {
            ExprKind::Block(ref block, _) => {
                if let Some(return_expression) = Self::return_expression(block) {
                    return Self::expression_returns_none(cx, &return_expression);
                }

                false
            },
            ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr),
            ExprKind::Path(ref qp) => {
                if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
                    cx.tables.qpath_res(qp, expression.hir_id)
                {
                    return cx.match_def_path(def_id, &OPTION_NONE);
                }

                false
            },
            _ => false,
        }
    }

    fn return_expression(block: &Block) -> Option<P<Expr>> {
        // Check if last expression is a return statement. Then, return the expression
        if_chain! {
            if block.stmts.len() == 1;
            if let Some(expr) = block.stmts.iter().last();
            if let StmtKind::Semi(ref expr) = expr.node;
            if let ExprKind::Ret(ref ret_expr) = expr.node;
            if let &Some(ref ret_expr) = ret_expr;

            then {
                return Some(ret_expr.clone());
            }
        }

        // Check for `return` without a semicolon.
        if_chain! {
            if block.stmts.len() == 0;
            if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.node);
            then {
                return Some(ret_expr.clone());
            }
        }

        None
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for QuestionMark {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        Self::check_is_none_and_early_return_none(cx, expr);
    }
}
<commit_msg>Fix question_mark.rs<commit_after>use if_chain::if_chain;
use rustc::hir::def::{DefKind, Res};
use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use syntax::ptr::P;

use crate::utils::paths::*;
use crate::utils::sugg::Sugg;
use crate::utils::{higher, match_type, span_lint_and_then, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for expressions that could be replaced by the question mark operator.
    ///
    /// **Why is this bad?** Question mark usage is more idiomatic.
    ///
    /// **Known problems:** None
    ///
    /// **Example:**
    /// ```ignore
    /// if option.is_none() {
    ///     return None;
    /// }
    /// ```
    ///
    /// Could be written:
    ///
    /// ```ignore
    /// option?;
    /// ```
    pub QUESTION_MARK,
    style,
    "checks for expressions that could be replaced by the question mark operator"
}

declare_lint_pass!(QuestionMark => [QUESTION_MARK]);

impl QuestionMark {
    /// Checks if the given expression on the given context matches the following structure:
    ///
    /// ```ignore
    /// if option.is_none() {
    ///    return None;
    /// }
    /// ```
    ///
    /// If it matches, it will suggest to use the question mark operator instead
    fn check_is_none_and_early_return_none(cx: &LateContext<'_, '_>, expr: &Expr) {
        if_chain! {
            if let Some((if_expr, body, else_)) = higher::if_block(&expr);
            if let ExprKind::MethodCall(segment, _, args) = &if_expr.node;
            if segment.ident.name == "is_none";
            if Self::expression_returns_none(cx, body);
            if let Some(subject) = args.get(0);
            if Self::is_option(cx, subject);

            then {
                let receiver_str = &Sugg::hir(cx, subject, "..");
                let mut replacement: Option<String> = None;
                if let Some(else_) = else_ {
                    if_chain! {
                        if let ExprKind::Block(block, None) = &else_.node;
                        if block.stmts.len() == 0;
                        if let Some(block_expr) = &block.expr;
                        if SpanlessEq::new(cx).ignore_fn().eq_expr(subject, block_expr);
                        then {
                            replacement = Some(format!("Some({}?)", receiver_str));
                        }
                    }
                } else if Self::moves_by_default(cx, subject) {
                        replacement = Some(format!("{}.as_ref()?;", receiver_str));
                } else {
                        replacement = Some(format!("{}?;", receiver_str));
                }

                if let Some(replacement_str) = replacement {
                    span_lint_and_then(
                        cx,
                        QUESTION_MARK,
                        expr.span,
                        "this block may be rewritten with the `?` operator",
                        |db| {
                            db.span_suggestion(
                                expr.span,
                                "replace_it_with",
                                replacement_str,
                                Applicability::MaybeIncorrect, // snippet
                            );
                        }
                    )
               }
            }
        }
    }

    fn moves_by_default(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
        let expr_ty = cx.tables.expr_ty(expression);

        !expr_ty.is_copy_modulo_regions(cx.tcx, cx.param_env, expression.span)
    }

    fn is_option(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
        let expr_ty = cx.tables.expr_ty(expression);

        match_type(cx, expr_ty, &OPTION)
    }

    fn expression_returns_none(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
        match expression.node {
            ExprKind::Block(ref block, _) => {
                if let Some(return_expression) = Self::return_expression(block) {
                    return Self::expression_returns_none(cx, &return_expression);
                }

                false
            },
            ExprKind::Ret(Some(ref expr)) => Self::expression_returns_none(cx, expr),
            ExprKind::Path(ref qp) => {
                if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
                    cx.tables.qpath_res(qp, expression.hir_id)
                {
                    return cx.match_def_path(def_id, &OPTION_NONE);
                }

                false
            },
            _ => false,
        }
    }

    fn return_expression(block: &Block) -> Option<P<Expr>> {
        // Check if last expression is a return statement. Then, return the expression
        if_chain! {
            if block.stmts.len() == 1;
            if let Some(expr) = block.stmts.iter().last();
            if let StmtKind::Semi(ref expr) = expr.node;
            if let ExprKind::Ret(ref ret_expr) = expr.node;
            if let &Some(ref ret_expr) = ret_expr;

            then {
                return Some(ret_expr.clone());
            }
        }

        // Check for `return` without a semicolon.
        if_chain! {
            if block.stmts.len() == 0;
            if let Some(ExprKind::Ret(Some(ret_expr))) = block.expr.as_ref().map(|e| &e.node);
            then {
                return Some(ret_expr.clone());
            }
        }

        None
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for QuestionMark {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
        Self::check_is_none_and_early_return_none(cx, expr);
    }
}
<|endoftext|>