<commit_before>use bindings::{
    jit_type_void_ptr,
    jit_type_ubyte,
    jit_type_sbyte,
    jit_type_ushort,
    jit_type_short,
    jit_type_uint,
    jit_type_int,
    jit_type_nuint,
    jit_type_nint,
    jit_type_float32,
    jit_type_float64,
    jit_type_long,
    jit_type_ulong,
    jit_type_sys_bool,
    jit_type_sys_char,

    jit_value_create_long_constant,
    jit_value_create_nint_constant,
    jit_value_create_float64_constant,
    jit_value_create_float32_constant
};
use function::{
    CDECL,
    Function
};
use get_type = types::get;
use libc::c_long;
use value::Value;
use std::c_str::CString;
use std::mem::transmute;
use types::Type;
use util::NativeRef;
/// A type that can be compiled into a LibJIT representation
pub trait Compile {
    /// Get a JIT representation of this value
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a>;
    /// Get the JIT type repr of the value
    fn jit_type(_:Option<Self>) -> Type;
}
impl Compile for () {
    #[inline(always)]
    fn compile(&self, func:&Function) -> Value {
        unsafe {
            NativeRef::from_ptr(jit_value_create_nint_constant(
                func.as_ptr(),
                jit_type_void_ptr,
                0
            ))
        }
    }
    #[inline(always)]
    fn jit_type(_:Option<()>) -> Type {
        unsafe {
            NativeRef::from_ptr(jit_type_void_ptr)
        }
    }
}
compile_prim!(f64, jit_type_float64, jit_value_create_float64_constant)
compile_prim!(f32, jit_type_float32, jit_value_create_float32_constant)
compile_prim!(int, jit_type_nint, jit_value_create_nint_constant, c_long)
compile_prim!(uint,jit_type_nuint, jit_value_create_nint_constant, c_long)
compile_prim!(i64, jit_type_long, jit_value_create_long_constant, c_long)
compile_prim!(u64, jit_type_ulong, jit_value_create_long_constant, c_long)
compile_prim!(i32, jit_type_int, jit_value_create_nint_constant, c_long)
compile_prim!(u32, jit_type_uint, jit_value_create_nint_constant, c_long)
compile_prim!(i16, jit_type_short, jit_value_create_nint_constant, c_long)
compile_prim!(u16, jit_type_ushort, jit_value_create_nint_constant, c_long)
compile_prim!(i8, jit_type_sbyte, jit_value_create_nint_constant, c_long)
compile_prim!(u8, jit_type_ubyte, jit_value_create_nint_constant, c_long)
compile_prim!(bool, jit_type_sys_bool, jit_value_create_nint_constant, c_long)
compile_prim!(char, jit_type_sys_char, jit_value_create_nint_constant, c_long)
impl Compile for *const u8 {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let c_str = unsafe { CString::new(transmute(*self), false) };
        let ty = jit!(&u8);
        let ptr = Value::new(func, ty);
        let length = c_str.len() + 1u;
        func.insn_store(&ptr, &func.insn_alloca(&func.insn_of(&length)));
        for enum_char in c_str.iter().enumerate() {
            let (pos, ch) = enum_char;
            let char_v = ch.compile(func);
            func.insn_store_relative(&ptr, pos as int, &char_v);
        }
        func.insn_store_relative(&ptr, c_str.len() as int, &func.insn_of(&'\0'));
        ptr
    }
    #[inline(always)]
    fn jit_type(_:Option<*const u8>) -> Type {
        ::get::<&u8>()
    }
}
impl<T:Compile> Compile for *mut T {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        unsafe {
            NativeRef::from_ptr(jit_value_create_nint_constant(
                func.as_ptr(),
                jit!(&T).as_ptr(),
                self.to_uint() as c_long
            ))
        }
    }
    #[inline(always)]
    fn jit_type(_:Option<*mut T>) -> Type {
        jit!(&T)
    }
}
impl<'s> Compile for CString {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ty = jit!(CString);
        let val = Value::new(func, ty.clone());
        let string:*const u8 = unsafe { transmute(self.as_ptr()) };
        func.insn_store_relative(&val, 0, &string.compile(func));
        func.insn_store_relative(&val, ty.find_name("is_owned").get_offset() as int, &true.compile(func));
        val
    }
    #[inline]
    fn jit_type(_:Option<CString>) -> Type {
        jit!(struct {
            "ptr": *const u8,
            "is_owned": bool
        })
    }
}
impl<'a> Compile for &'a str {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let str_ptr = {
            let ty = ::get::<*const u8>();
            let ptr = Value::new(func, ty);
            func.insn_store(&ptr, &func.insn_alloca(&func.insn_of(&self.len())));
            for enum_char in self.bytes().enumerate() {
                let (pos, ch) = enum_char;
                let char_v = ch.compile(func);
                func.insn_store_relative(&ptr, pos as int, &char_v);
            }
            ptr
        };
        let ty = ::get::<&'a str>();
        let val = Value::new(func, ty.clone());
        func.insn_store_relative(&val, 0, &str_ptr);
        func.insn_store_relative(&val, ty.find_name("len").get_offset() as int, &self.len().compile(func));
        val
    }
    #[inline]
    fn jit_type(_:Option<&'a str>) -> Type {
        jit!(struct {
            "ptr": *const u8,
            "len": uint
        })
    }
}
impl<'a> Compile for String {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let str_ptr = {
            let ty = ::get::<*const u8>();
            let ptr = Value::new(func, ty);
            func.insn_store(&ptr, &func.insn_alloca(&func.insn_of(&self.len())));
            for (pos, ch) in self.as_slice().bytes().enumerate() {
                let char_v = ch.compile(func);
                func.insn_store_relative(&ptr, pos as int, &char_v);
            }
            ptr
        };
        let ty = ::get::<String>();
        let val = Value::new(func, ty.clone());
        let length = self.len().compile(func);
        func.insn_store_relative(&val, 0, &length);
        func.insn_store_relative(&val, ty.clone().find_name("cap").get_offset() as int, &length);
        func.insn_store_relative(&val, ty.find_name("ptr").get_offset() as int, &str_ptr);
        val
    }
    #[inline]
    fn jit_type(_:Option<String>) -> Type {
        jit!(struct {
            "len": uint,
            "cap": uint,
            "ptr": &u8
        })
    }
}
impl<'a, T:Compile> Compile for Vec<T> {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let vec_ptr = {
            let ty = ::get::<&T>();
            let inner_ty = jit!(T);
            let ptr = Value::new(func, ty);
            let ptr_size = self.len() * inner_ty.get_size();
            let ptr_size = func.insn_of(&ptr_size);
            func.insn_store(&ptr, &func.insn_alloca(&ptr_size));
            for (pos, val) in self.iter().enumerate() {
                let val_v = val.compile(func);
                func.insn_store_relative(&ptr, pos as int, &val_v);
            }
            ptr
        };
        let ty = ::get::<String>();
        let val = Value::new(func, ty.clone());
        let length = func.insn_of(&self.len());
        func.insn_store_relative(&val, 0, &length);
        func.insn_store_relative(&val, ty.clone().find_name("cap").get_offset() as int, &length);
        func.insn_store_relative(&val, ty.find_name("ptr").get_offset() as int, &vec_ptr);
        val
    }
    #[inline]
    fn jit_type(_:Option<Vec<T>>) -> Type {
        jit!(struct {
            "len": uint,
            "cap": uint,
            "ptr": &T
        })
    }
}
impl<'a, T:Compile> Compile for &'a T {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        unsafe {
            NativeRef::from_ptr(jit_value_create_nint_constant(
                func.as_ptr(),
                jit!(T).as_ptr(),
                (*self as *const T).to_uint() as c_long
            ))
        }
    }
    #[inline(always)]
    fn jit_type(_:Option<&'a T>) -> Type {
        Type::create_pointer(jit!(T))
    }
}
impl<R:Compile> Compile for fn() -> R {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ptr = (self as *const fn() -> R).to_uint().compile(func);
        func.insn_convert(&ptr, get_type::<fn() -> R>(), false)
    }
    #[inline(always)]
    fn jit_type(_:Option<fn() -> R>) -> Type {
        Type::create_signature(CDECL, jit!(R), &mut [])
    }
}
impl<A:Compile, R:Compile> Compile for fn(A) -> R {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ptr = (self as *const fn(A) -> R).to_uint().compile(func);
        func.insn_convert(&ptr, get_type::<fn(A) -> R>(), false)
    }
    #[inline(always)]
    fn jit_type(_:Option<fn(A) -> R>) -> Type {
        Type::create_signature(CDECL, jit!(R), &mut [jit!(A)])
    }
}
impl<A:Compile, B:Compile, R:Compile> Compile for fn(A, B) -> R {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ptr = (self as *const fn(A, B) -> R).to_uint().compile(func);
        func.insn_convert(&ptr, get_type::<fn(A, B) -> R>(), false)
    }
    #[inline(always)]
    fn jit_type(_:Option<fn(A, B) -> R>) -> Type {
        Type::create_signature(CDECL, jit!(R), &mut [jit!(A), jit!(B)])
    }
}
impl<A:Compile, B:Compile, C:Compile, R:Compile> Compile for fn(A, B, C) -> R {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ptr = (self as *const fn(A, B, C) -> R).to_uint().compile(func);
        func.insn_convert(&ptr, get_type::<fn(A, B, C) -> R>(), false)
    }
    #[inline(always)]
    fn jit_type(_:Option<fn(A, B, C) -> R>) -> Type {
        Type::create_signature(CDECL, jit!(R), &mut [jit!(A), jit!(B), jit!(C)])
    }
}<commit_msg>Fix void value generation<commit_after>use bindings::{
    jit_type_ubyte,
    jit_type_sbyte,
    jit_type_ushort,
    jit_type_short,
    jit_type_uint,
    jit_type_int,
    jit_type_nuint,
    jit_type_nint,
    jit_type_float32,
    jit_type_float64,
    jit_type_long,
    jit_type_ulong,
    jit_type_sys_bool,
    jit_type_sys_char,
    jit_type_void,

    jit_value_create_long_constant,
    jit_value_create_nint_constant,
    jit_value_create_float64_constant,
    jit_value_create_float32_constant
};
use function::{
    CDECL,
    Function
};
use get_type = types::get;
use libc::c_long;
use value::Value;
use std::c_str::CString;
use std::mem::transmute;
use types::Type;
use util::NativeRef;
/// A type that can be compiled into a LibJIT representation
pub trait Compile {
    /// Get a JIT representation of this value
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a>;
    /// Get the JIT type repr of the value
    fn jit_type(_:Option<Self>) -> Type;
}
impl Compile for () {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ty = ::get::<()>();
        Value::new(func, ty)
    }
    #[inline(always)]
    fn jit_type(_:Option<()>) -> Type {
        unsafe {
            NativeRef::from_ptr(jit_type_void)
        }
    }
}
compile_prim!(f64, jit_type_float64, jit_value_create_float64_constant)
compile_prim!(f32, jit_type_float32, jit_value_create_float32_constant)
compile_prim!(int, jit_type_nint, jit_value_create_nint_constant, c_long)
compile_prim!(uint,jit_type_nuint, jit_value_create_nint_constant, c_long)
compile_prim!(i64, jit_type_long, jit_value_create_long_constant, c_long)
compile_prim!(u64, jit_type_ulong, jit_value_create_long_constant, c_long)
compile_prim!(i32, jit_type_int, jit_value_create_nint_constant, c_long)
compile_prim!(u32, jit_type_uint, jit_value_create_nint_constant, c_long)
compile_prim!(i16, jit_type_short, jit_value_create_nint_constant, c_long)
compile_prim!(u16, jit_type_ushort, jit_value_create_nint_constant, c_long)
compile_prim!(i8, jit_type_sbyte, jit_value_create_nint_constant, c_long)
compile_prim!(u8, jit_type_ubyte, jit_value_create_nint_constant, c_long)
compile_prim!(bool, jit_type_sys_bool, jit_value_create_nint_constant, c_long)
compile_prim!(char, jit_type_sys_char, jit_value_create_nint_constant, c_long)
impl Compile for *const u8 {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let c_str = unsafe { CString::new(transmute(*self), false) };
        let ty = jit!(&u8);
        let ptr = Value::new(func, ty);
        let length = c_str.len() + 1u;
        func.insn_store(&ptr, &func.insn_alloca(&func.insn_of(&length)));
        for enum_char in c_str.iter().enumerate() {
            let (pos, ch) = enum_char;
            let char_v = ch.compile(func);
            func.insn_store_relative(&ptr, pos as int, &char_v);
        }
        func.insn_store_relative(&ptr, c_str.len() as int, &func.insn_of(&'\0'));
        ptr
    }
    #[inline(always)]
    fn jit_type(_:Option<*const u8>) -> Type {
        ::get::<&u8>()
    }
}
impl<T:Compile> Compile for *mut T {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        unsafe {
            NativeRef::from_ptr(jit_value_create_nint_constant(
                func.as_ptr(),
                jit!(&T).as_ptr(),
                self.to_uint() as c_long
            ))
        }
    }
    #[inline(always)]
    fn jit_type(_:Option<*mut T>) -> Type {
        jit!(&T)
    }
}
impl<'s> Compile for CString {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ty = jit!(CString);
        let val = Value::new(func, ty.clone());
        let string:*const u8 = unsafe { transmute(self.as_ptr()) };
        func.insn_store_relative(&val, 0, &string.compile(func));
        func.insn_store_relative(&val, ty.find_name("is_owned").get_offset() as int, &true.compile(func));
        val
    }
    #[inline]
    fn jit_type(_:Option<CString>) -> Type {
        jit!(struct {
            "ptr": *const u8,
            "is_owned": bool
        })
    }
}
impl<'a> Compile for &'a str {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let str_ptr = {
            let ty = ::get::<*const u8>();
            let ptr = Value::new(func, ty);
            func.insn_store(&ptr, &func.insn_alloca(&func.insn_of(&self.len())));
            for enum_char in self.bytes().enumerate() {
                let (pos, ch) = enum_char;
                let char_v = ch.compile(func);
                func.insn_store_relative(&ptr, pos as int, &char_v);
            }
            ptr
        };
        let ty = ::get::<&'a str>();
        let val = Value::new(func, ty.clone());
        func.insn_store_relative(&val, 0, &str_ptr);
        func.insn_store_relative(&val, ty.find_name("len").get_offset() as int, &self.len().compile(func));
        val
    }
    #[inline]
    fn jit_type(_:Option<&'a str>) -> Type {
        jit!(struct {
            "ptr": *const u8,
            "len": uint
        })
    }
}
impl<'a> Compile for String {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let str_ptr = {
            let ty = ::get::<*const u8>();
            let ptr = Value::new(func, ty);
            func.insn_store(&ptr, &func.insn_alloca(&func.insn_of(&self.len())));
            for (pos, ch) in self.as_slice().bytes().enumerate() {
                let char_v = ch.compile(func);
                func.insn_store_relative(&ptr, pos as int, &char_v);
            }
            ptr
        };
        let ty = ::get::<String>();
        let val = Value::new(func, ty.clone());
        let length = self.len().compile(func);
        func.insn_store_relative(&val, 0, &length);
        func.insn_store_relative(&val, ty.clone().find_name("cap").get_offset() as int, &length);
        func.insn_store_relative(&val, ty.find_name("ptr").get_offset() as int, &str_ptr);
        val
    }
    #[inline]
    fn jit_type(_:Option<String>) -> Type {
        jit!(struct {
            "len": uint,
            "cap": uint,
            "ptr": &u8
        })
    }
}
impl<'a, T:Compile> Compile for Vec<T> {
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let vec_ptr = {
            let ty = ::get::<&T>();
            let inner_ty = jit!(T);
            let ptr = Value::new(func, ty);
            let ptr_size = self.len() * inner_ty.get_size();
            let ptr_size = func.insn_of(&ptr_size);
            func.insn_store(&ptr, &func.insn_alloca(&ptr_size));
            for (pos, val) in self.iter().enumerate() {
                let val_v = val.compile(func);
                func.insn_store_relative(&ptr, pos as int, &val_v);
            }
            ptr
        };
        let ty = ::get::<String>();
        let val = Value::new(func, ty.clone());
        let length = func.insn_of(&self.len());
        func.insn_store_relative(&val, 0, &length);
        func.insn_store_relative(&val, ty.clone().find_name("cap").get_offset() as int, &length);
        func.insn_store_relative(&val, ty.find_name("ptr").get_offset() as int, &vec_ptr);
        val
    }
    #[inline]
    fn jit_type(_:Option<Vec<T>>) -> Type {
        jit!(struct {
            "len": uint,
            "cap": uint,
            "ptr": &T
        })
    }
}
impl<'a, T:Compile> Compile for &'a T {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        unsafe {
            NativeRef::from_ptr(jit_value_create_nint_constant(
                func.as_ptr(),
                jit!(T).as_ptr(),
                (*self as *const T).to_uint() as c_long
            ))
        }
    }
    #[inline(always)]
    fn jit_type(_:Option<&'a T>) -> Type {
        Type::create_pointer(jit!(T))
    }
}
impl<R:Compile> Compile for fn() -> R {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ptr = (self as *const fn() -> R).to_uint().compile(func);
        func.insn_convert(&ptr, get_type::<fn() -> R>(), false)
    }
    #[inline(always)]
    fn jit_type(_:Option<fn() -> R>) -> Type {
        Type::create_signature(CDECL, jit!(R), &mut [])
    }
}
impl<A:Compile, R:Compile> Compile for fn(A) -> R {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ptr = (self as *const fn(A) -> R).to_uint().compile(func);
        func.insn_convert(&ptr, get_type::<fn(A) -> R>(), false)
    }
    #[inline(always)]
    fn jit_type(_:Option<fn(A) -> R>) -> Type {
        Type::create_signature(CDECL, jit!(R), &mut [jit!(A)])
    }
}
impl<A:Compile, B:Compile, R:Compile> Compile for fn(A, B) -> R {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ptr = (self as *const fn(A, B) -> R).to_uint().compile(func);
        func.insn_convert(&ptr, get_type::<fn(A, B) -> R>(), false)
    }
    #[inline(always)]
    fn jit_type(_:Option<fn(A, B) -> R>) -> Type {
        Type::create_signature(CDECL, jit!(R), &mut [jit!(A), jit!(B)])
    }
}
impl<A:Compile, B:Compile, C:Compile, R:Compile> Compile for fn(A, B, C) -> R {
    #[inline(always)]
    fn compile<'a>(&self, func:&'a Function<'a>) -> Value<'a> {
        let ptr = (self as *const fn(A, B, C) -> R).to_uint().compile(func);
        func.insn_convert(&ptr, get_type::<fn(A, B, C) -> R>(), false)
    }
    #[inline(always)]
    fn jit_type(_:Option<fn(A, B, C) -> R>) -> Type {
        Type::create_signature(CDECL, jit!(R), &mut [jit!(A), jit!(B), jit!(C)])
    }
}<|endoftext|>


<commit_before>use std::f32::consts::{PI, FRAC_1_PI};
use std::path::Path;
use std::cmp::max;

use na::{Norm, Inverse, Origin, zero, origin};

use ::{Vector, Vector3f, Point2i, Point2f, Point3f, Transform};
use geometry::{spherical_phi, spherical_theta};
use interaction::{Interaction, SurfaceInteraction};
use light::{Light, LightFlags, VisibilityTester, INFINITE};
use mipmap::{MIPMap, WrapMode};
use ray::Ray;
use sampling::Distribution2D;
use spectrum::Spectrum;

pub struct InfiniteAreaLight {
    light_to_world: Transform,
    world_to_light: Transform,
    n_samples: u32,
    l_map: Box<MIPMap<Spectrum>>,
    world_center: Point3f,
    world_radius: f32,
    distribution: Box<Distribution2D>,
}

impl InfiniteAreaLight {
    pub fn new(l2w: Transform,
               n_samples: u32,
               power: Spectrum,
               texmap: &Path)
               -> InfiniteAreaLight {
        // Read texel data from texmap and initialise Lmap TODO
        let resolution = Point2i::new(1, 1);
        let l_map = Box::new(MIPMap::new(&resolution, &[power; 1], false, 0.0, WrapMode::Repeat));
        // initialize sampling PDFs for infinite area light TODO
        // - compute scalar-valued image img from environment map
        let (width, height) = (resolution.x as usize, resolution.y as usize);
        let filter = 1.0 / max(width, height) as f32;
        let mut img = Vec::with_capacity(width * height);
        for v in 0..height {
            let vp = v as f32 / height as f32;
            let sin_theta = (PI * (v as f32 + 0.5) / height as f32).sin();
            for u in 0..width {
                let up = u as f32 / width as f32;
                img[u + v * width] = l_map.lookup(&Point2f::new(up, vp), filter).y() * sin_theta;
            }
        }
        // - compute sampling distributions for rows and columns of image
        let distribution = Box::new(Distribution2D::new(&img[..], width, height));

        InfiniteAreaLight {
            light_to_world: l2w,
            world_to_light: l2w.inverse().unwrap(),
            n_samples: n_samples,
            l_map: l_map,
            world_center: origin(),
            world_radius: 100.0, // TODO
            distribution: distribution,
        }
    }
}

impl Light for InfiniteAreaLight {
    fn sample_li(&self,
                 isect: &SurfaceInteraction,
                 wo: &Vector,
                 u: &Point2f)
                 -> (Spectrum, Vector, f32, VisibilityTester) {
        // Find (u, v) sample coordinates in infinite light texture
        let (uv, map_pdf) = self.distribution.sample_continuous(u);
        if map_pdf == 0.0 {
            return (Spectrum::black(),
                    Vector3f::new(0.0, 0.0, 0.0),
                    0.0,
                    VisibilityTester::new(Interaction::from_point(&origin()),
                                          Interaction::from_point(&origin())));
        }
        // Convert infinite light sample point to direction
        let theta = uv[1] * PI;
        let phi = uv[0] * 2.0 * PI;
        let cos_theta = theta.cos();
        let sin_theta = theta.sin();
        let cos_phi = phi.cos();
        let sin_phi = phi.sin();
        let wi = self.light_to_world *
                 Vector3f::new(sin_theta * cos_phi, sin_theta * sin_phi, cos_theta);
        // Compute PDF for sampled infinite light direction
        let pdf = if sin_theta == 0.0 {
            0.0
        } else {
            map_pdf / (2.0 * PI * PI * sin_theta)
        };
        // Return radiance value for infinite light direction
        let target = isect.p + wi * (2.0 * self.world_radius);
        let vis = VisibilityTester::new(isect.into(), Interaction::from_point(&target));
        (self.l_map.lookup(&uv, 0.0), wi, pdf, vis)
    }

    fn pdf_li(&self, si: &SurfaceInteraction, w: &Vector) -> f32 {
        let wi = self.world_to_light * *w;
        let theta = spherical_theta(&wi);
        let phi = spherical_phi(&wi);
        let sin_theta = theta.sin();

        if sin_theta == 0.0 {
            0.0
        } else {
            self.distribution.pdf(&Point2f::new(phi * FRAC_1_PI * 0.5, theta * FRAC_1_PI)) /
            (2.0 * PI * PI * sin_theta)
        }
    }

    fn n_samples(&self) -> u32 {
        self.n_samples
    }

    fn flags(&self) -> LightFlags {
        INFINITE
    }

    fn power(&self) -> Spectrum {
        PI * self.world_radius * self.world_radius * self.l_map.lookup(&Point2f::new(0.5, 0.5), 0.5)
    }

    fn le(&self, ray: &Ray) -> Spectrum {
        let w = (self.world_to_light * ray.d).normalize();
        let st = Point2f::new(spherical_phi(&w) * FRAC_1_PI * 0.5,
                              spherical_theta(&w) * FRAC_1_PI);

        self.l_map.lookup(&st, 0.0)
    }
}
<commit_msg>Fix some bugs in InfiniteAreaLight<commit_after>use std::f32::consts::{PI, FRAC_1_PI};
use std::path::Path;
use std::cmp::max;

use na::{Norm, Inverse, Origin, zero, origin};

use ::{Vector, Vector3f, Point2i, Point2f, Point3f, Transform};
use geometry::{spherical_phi, spherical_theta};
use interaction::{Interaction, SurfaceInteraction};
use light::{Light, LightFlags, VisibilityTester, INFINITE};
use mipmap::{MIPMap, WrapMode};
use ray::Ray;
use sampling::Distribution2D;
use spectrum::Spectrum;

pub struct InfiniteAreaLight {
    light_to_world: Transform,
    world_to_light: Transform,
    n_samples: u32,
    l_map: Box<MIPMap<Spectrum>>,
    world_center: Point3f,
    world_radius: f32,
    distribution: Box<Distribution2D>,
}

impl InfiniteAreaLight {
    pub fn new(l2w: Transform,
               n_samples: u32,
               power: Spectrum,
               texmap: &Path)
               -> InfiniteAreaLight {
        // Read texel data from texmap and initialise Lmap TODO
        let resolution = Point2i::new(1, 1);
        let l_map = Box::new(MIPMap::new(&resolution, &[power; 1], false, 0.0, WrapMode::Repeat));
        // initialize sampling PDFs for infinite area light TODO
        // - compute scalar-valued image img from environment map
        let (width, height) = (2 * l_map.width(), 2 * l_map.height());
        let filter = 0.5 / max(width, height) as f32;
        let mut img = Vec::with_capacity(width * height);
        for v in 0..height {
            let vp = (v as f32 + 0.5) / height as f32;
            let sin_theta = (PI * (v as f32 + 0.5) / height as f32).sin();
            for u in 0..width {
                let up = (u as f32 + 0.5) / width as f32;
                img.push(l_map.lookup(&Point2f::new(up, vp), filter).y() * sin_theta);
            }
        }
        // - compute sampling distributions for rows and columns of image
        let distribution = Box::new(Distribution2D::new(&img[..], width, height));

        InfiniteAreaLight {
            light_to_world: l2w,
            world_to_light: l2w.inverse().unwrap(),
            n_samples: n_samples,
            l_map: l_map,
            world_center: origin(),
            world_radius: 100.0, // TODO
            distribution: distribution,
        }
    }
}

impl Light for InfiniteAreaLight {
    fn sample_li(&self,
                 isect: &SurfaceInteraction,
                 wo: &Vector,
                 u: &Point2f)
                 -> (Spectrum, Vector, f32, VisibilityTester) {
        // Find (u, v) sample coordinates in infinite light texture
        let (uv, map_pdf) = self.distribution.sample_continuous(u);
        if map_pdf == 0.0 {
            return (Spectrum::black(),
                    Vector3f::new(0.0, 0.0, 0.0),
                    0.0,
                    VisibilityTester::new(Interaction::from_point(&origin()),
                                          Interaction::from_point(&origin())));
        }
        // Convert infinite light sample point to direction
        let theta = uv[1] * PI;
        let phi = uv[0] * 2.0 * PI;
        let cos_theta = theta.cos();
        let sin_theta = theta.sin();
        let cos_phi = phi.cos();
        let sin_phi = phi.sin();
        let wi = self.light_to_world *
                 Vector3f::new(sin_theta * cos_phi, sin_theta * sin_phi, cos_theta);
        // Compute PDF for sampled infinite light direction
        let pdf = if sin_theta == 0.0 {
            0.0
        } else {
            map_pdf / (2.0 * PI * PI * sin_theta)
        };
        // Return radiance value for infinite light direction
        let target = isect.p + wi * (2.0 * self.world_radius);
        let vis = VisibilityTester::new(isect.into(), Interaction::from_point(&target));
        (self.l_map.lookup(&uv, 0.0), wi, pdf, vis)
    }

    fn pdf_li(&self, si: &SurfaceInteraction, w: &Vector) -> f32 {
        let wi = self.world_to_light * *w;
        let theta = spherical_theta(&wi);
        let phi = spherical_phi(&wi);
        let sin_theta = theta.sin();

        if sin_theta == 0.0 {
            0.0
        } else {
            self.distribution.pdf(&Point2f::new(phi * FRAC_1_PI * 0.5, theta * FRAC_1_PI)) /
            (2.0 * PI * PI * sin_theta)
        }
    }

    fn n_samples(&self) -> u32 {
        self.n_samples
    }

    fn flags(&self) -> LightFlags {
        INFINITE
    }

    fn power(&self) -> Spectrum {
        PI * self.world_radius * self.world_radius * self.l_map.lookup(&Point2f::new(0.5, 0.5), 0.5)
    }

    fn le(&self, ray: &Ray) -> Spectrum {
        let w = (self.world_to_light * ray.d).normalize();
        let st = Point2f::new(spherical_phi(&w) * FRAC_1_PI * 0.5,
                              spherical_theta(&w) * FRAC_1_PI);

        self.l_map.lookup(&st, 0.0)
    }
}
<|endoftext|>


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

#[macro_use] extern crate procedural_masquerade;
extern crate phf_codegen;
extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;

use std::ascii::AsciiExt;

define_proc_macros! {
    /// Input: the arms of a `match` expression.
    ///
    /// Output: a `MAX_LENGTH` constant with the length of the longest string pattern.
    ///
    /// Panic if the arms contain non-string patterns,
    /// or string patterns that contains ASCII uppercase letters.
    #[allow(non_snake_case)]
    pub fn cssparser_internal__assert_ascii_lowercase__max_len(input: &str) -> String {
        let expr = syn::parse_expr(&format!("match x {{ {} }}", input)).unwrap();
        let arms = match expr {
            syn::Expr { node: syn::ExprKind::Match(_, ref arms), .. } => arms,
            _ => panic!("expected a match expression, got {:?}", expr)
        };
        max_len(arms.iter().flat_map(|arm| &arm.pats).filter_map(|pattern| {
            let expr = match *pattern {
                syn::Pat::Lit(ref expr) => expr,
                syn::Pat::Wild |
                syn::Pat::Ident(_, _, None) => return None,
                syn::Pat::Ident(_, _, Some(ref sub_pattern)) => {
                    match **sub_pattern {
                        syn::Pat::Lit(ref expr) => expr,
                        syn::Pat::Wild => return None,
                        _ => panic!("expected string or wildcard pattern, got {:?}", pattern)
                    }
                }
                _ => panic!("expected string or wildcard pattern, got {:?}", pattern)
            };
            match **expr {
                syn::Expr { node: syn::ExprKind::Lit(syn::Lit::Str(ref string, _)), .. } => {
                    assert_eq!(*string, string.to_ascii_lowercase(),
                               "string patterns must be given in ASCII lowercase");
                    Some(string.len())
                }
                _ => panic!("expected string pattern, got {:?}", expr)
            }
        }))
    }

    /// Input: string literals with no separator
    ///
    /// Output: a `MAX_LENGTH` constant with the length of the longest string.
    #[allow(non_snake_case)]
    pub fn cssparser_internal__max_len(input: &str) -> String {
        max_len(syn::parse_token_trees(input).unwrap().iter().map(|tt| string_literal(tt).len()))
    }

    /// Input: parsed as token trees. The first TT is a type. (Can be wrapped in parens.)
    /// following TTs are grouped in pairs, each pair being a key as a string literal
    /// and the corresponding value as a const expression.
    ///
    /// Output: a rust-phf map, with keys ASCII-lowercased:
    /// ```
    /// static MAP: &'static ::cssparser::phf::Map<&'static str, $ValueType> = …;
    /// ```
    #[allow(non_snake_case)]
    pub fn cssparser_internal__phf_map(input: &str) -> String {
        let token_trees = syn::parse_token_trees(input).unwrap();
        let value_type = &token_trees[0];
        let pairs: Vec<_> = token_trees[1..].chunks(2).map(|chunk| {
            let key = string_literal(&chunk[0]);
            let value = &chunk[1];
            (key.to_ascii_lowercase(), quote!(#value).to_string())
        }).collect();

        let mut map = phf_codegen::Map::new();
        map.phf_path("::cssparser::_internal__phf");
        for &(ref key, ref value) in &pairs {
            map.entry(&**key, &**value);
        }

        let mut tokens = quote! {
            static MAP: ::cssparser::_internal__phf::Map<&'static str, #value_type> =
        };
        let mut initializer_bytes = Vec::new();
        map.build(&mut initializer_bytes).unwrap();
        tokens.append(::std::str::from_utf8(&initializer_bytes).unwrap());
        tokens.append(";");
        tokens.into_string()
    }
}

fn max_len<I: Iterator<Item=usize>>(lengths: I) -> String {
    let max_length = lengths.max().expect("expected at least one string");
    quote!( const MAX_LENGTH: usize = #max_length; ).into_string()
}

fn string_literal(token: &syn::TokenTree) -> &str {
    match *token {
        syn::TokenTree::Token(syn::Token::Literal(syn::Lit::Str(ref string, _))) => string,
        _ => panic!("expected string literal, got {:?}", token)
    }
}
<commit_msg>Auto merge of #131 - servo:jdm-patch-1, r=emilio<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#[macro_use] extern crate procedural_masquerade;
extern crate phf_codegen;
extern crate proc_macro;
#[macro_use] extern crate quote;
extern crate syn;

use std::ascii::AsciiExt;

define_proc_macros! {
    /// Input: the arms of a `match` expression.
    ///
    /// Output: a `MAX_LENGTH` constant with the length of the longest string pattern.
    ///
    /// Panic if the arms contain non-string patterns,
    /// or string patterns that contains ASCII uppercase letters.
    #[allow(non_snake_case)]
    pub fn cssparser_internal__assert_ascii_lowercase__max_len(input: &str) -> String {
        let expr = syn::parse_expr(&format!("match x {{ {} }}", input)).unwrap();
        let arms = match expr {
            syn::Expr { node: syn::ExprKind::Match(_, ref arms), .. } => arms,
            _ => panic!("expected a match expression, got {:?}", expr)
        };
        max_len(arms.iter().flat_map(|arm| &arm.pats).filter_map(|pattern| {
            let expr = match *pattern {
                syn::Pat::Lit(ref expr) => expr,
                syn::Pat::Wild |
                syn::Pat::Ident(_, _, None) => return None,
                syn::Pat::Ident(_, _, Some(ref sub_pattern)) => {
                    match **sub_pattern {
                        syn::Pat::Lit(ref expr) => expr,
                        syn::Pat::Wild => return None,
                        _ => panic!("expected string or wildcard pattern, got {:?}", pattern)
                    }
                }
                _ => panic!("expected string or wildcard pattern, got {:?}", pattern)
            };
            match **expr {
                syn::Expr { node: syn::ExprKind::Lit(syn::Lit::Str(ref string, _)), .. } => {
                    assert_eq!(*string, string.to_ascii_lowercase(),
                               "string patterns must be given in ASCII lowercase");
                    Some(string.len())
                }
                _ => panic!("expected string pattern, got {:?}", expr)
            }
        }))
    }

    /// Input: string literals with no separator
    ///
    /// Output: a `MAX_LENGTH` constant with the length of the longest string.
    #[allow(non_snake_case)]
    pub fn cssparser_internal__max_len(input: &str) -> String {
        max_len(syn::parse_token_trees(input).unwrap().iter().map(|tt| string_literal(tt).len()))
    }

    /// Input: parsed as token trees. The first TT is a type. (Can be wrapped in parens.)
    /// following TTs are grouped in pairs, each pair being a key as a string literal
    /// and the corresponding value as a const expression.
    ///
    /// Output: a rust-phf map, with keys ASCII-lowercased:
    /// ```text
    /// static MAP: &'static ::cssparser::phf::Map<&'static str, $ValueType> = …;
    /// ```
    #[allow(non_snake_case)]
    pub fn cssparser_internal__phf_map(input: &str) -> String {
        let token_trees = syn::parse_token_trees(input).unwrap();
        let value_type = &token_trees[0];
        let pairs: Vec<_> = token_trees[1..].chunks(2).map(|chunk| {
            let key = string_literal(&chunk[0]);
            let value = &chunk[1];
            (key.to_ascii_lowercase(), quote!(#value).to_string())
        }).collect();

        let mut map = phf_codegen::Map::new();
        map.phf_path("::cssparser::_internal__phf");
        for &(ref key, ref value) in &pairs {
            map.entry(&**key, &**value);
        }

        let mut tokens = quote! {
            static MAP: ::cssparser::_internal__phf::Map<&'static str, #value_type> =
        };
        let mut initializer_bytes = Vec::new();
        map.build(&mut initializer_bytes).unwrap();
        tokens.append(::std::str::from_utf8(&initializer_bytes).unwrap());
        tokens.append(";");
        tokens.into_string()
    }
}

fn max_len<I: Iterator<Item=usize>>(lengths: I) -> String {
    let max_length = lengths.max().expect("expected at least one string");
    quote!( const MAX_LENGTH: usize = #max_length; ).into_string()
}

fn string_literal(token: &syn::TokenTree) -> &str {
    match *token {
        syn::TokenTree::Token(syn::Token::Literal(syn::Lit::Str(ref string, _))) => string,
        _ => panic!("expected string literal, got {:?}", token)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ast::{Data, Container, Style};
use attr::{Identifier, EnumTag};
use Ctxt;

/// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &Container) {
    check_getter(cx, cont);
    check_identifier(cx, cont);
    check_variant_skip_attrs(cx, cont);
    check_internally_tagged_variant_name_conflict(cx, cont);
}

/// Getters are only allowed inside structs (not enums) with the `remote`
/// attribute.
fn check_getter(cx: &Ctxt, cont: &Container) {
    match cont.data {
        Data::Enum(_) => {
            if cont.data.has_getter() {
                cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
            }
        }
        Data::Struct(_, _) => {
            if cont.data.has_getter() && cont.attrs.remote().is_none() {
                cx.error(
                    "#[serde(getter = \"...\")] can only be used in structs \
                     that have #[serde(remote = \"...\")]",
                );
            }
        }
    }
}

/// The `other` attribute must be used at most once and it must be the last
/// variant of an enum that has the `field_identifier` attribute.
///
/// Inside a `variant_identifier` all variants must be unit variants. Inside a
/// `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return;
        }
    };

    for (i, variant) in variants.iter().enumerate() {
        match (
            variant.style,
            cont.attrs.identifier(),
            variant.attrs.other(),
        ) {
            // The `other` attribute may only be used in a field_identifier.
            (_, Identifier::Variant, true) | (_, Identifier::No, true) => {
                cx.error("#[serde(other)] may only be used inside a field_identifier");
            }

            // Variant with `other` attribute must be the last one.
            (Style::Unit, Identifier::Field, true) => {
                if i < variants.len() - 1 {
                    cx.error("#[serde(other)] must be the last variant");
                }
            }

            // Variant with `other` attribute must be a unit variant.
            (_, Identifier::Field, true) => {
                cx.error("#[serde(other)] must be on a unit variant");
            }

            // Any sort of variant is allowed if this is not an identifier.
            (_, Identifier::No, false) => {}

            // Unit variant without `other` attribute is always fine.
            (Style::Unit, _, false) => {}

            // The last field is allowed to be a newtype catch-all.
            (Style::Newtype, Identifier::Field, false) => {
                if i < variants.len() - 1 {
                    cx.error(format!("`{}` must be the last variant", variant.ident));
                }
            }

            (_, Identifier::Field, false) => {
                cx.error("field_identifier may only contain unit variants");
            }

            (_, Identifier::Variant, false) => {
                cx.error("variant_identifier may only contain unit variants");
            }
        }
    }
}

/// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return;
        }
    };

    for variant in variants.iter() {
        if variant.attrs.serialize_with().is_some() {
            if variant.attrs.skip_serializing() {
                cx.error(format!(
                    "variant `{}` cannot have both #[serde(serialize_with)] and \
                     #[serde(skip_serializing)]",
                    variant.ident
                ));
            }

            for (i, field) in variant.fields.iter().enumerate() {
                let ident = field
                    .ident
                    .as_ref()
                    .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));

                if field.attrs.skip_serializing() {
                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(serialize_with)] and \
                         a field {} marked with #[serde(skip_serializing)]",
                        variant.ident, ident
                    ));
                }

                if field.attrs.skip_serializing_if().is_some() {
                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(serialize_with)] and \
                         a field {} marked with #[serde(skip_serializing_if)]",
                        variant.ident, ident
                    ));
                }
            }
        }

        if variant.attrs.deserialize_with().is_some() {
            if variant.attrs.skip_deserializing() {
                cx.error(format!(
                    "variant `{}` cannot have both #[serde(deserialize_with)] and \
                     #[serde(skip_deserializing)]",
                    variant.ident
                ));
            }

            for (i, field) in variant.fields.iter().enumerate() {
                if field.attrs.skip_deserializing() {
                    let ident = field
                        .ident
                        .as_ref()
                        .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));

                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(deserialize_with)] \
                         and a field {} marked with #[serde(skip_deserializing)]",
                        variant.ident, ident
                    ));
                }
            }
        }
    }
}

fn check_internally_tagged_variant_name_conflict(
    cx: &Ctxt,
    cont: &Container,
) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => return,
    };

    let tag = match *cont.attrs.tag() {
        EnumTag::Internal { ref tag } => tag.as_str(),
        EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
    };

    let diagnose_conflict = || {
        let message = format!(
            "variant field name `{}` conflicts with internal tag",
            tag
        );
        cx.error(message);
    };

    for variant in variants {
        match variant.style {
            Style::Struct => {
                for field in &variant.fields {
                    let check_ser = !field.attrs.skip_serializing();
                    let check_de = !field.attrs.skip_deserializing();
                    let name = field.attrs.name();
                    let ser_name = name.serialize_name();
                    let de_name = name.deserialize_name();

                    if check_ser && ser_name == tag || check_de && de_name == tag {
                        diagnose_conflict();
                        return;
                    }
                }
            },
            _ => {},
        }
    }
}
<commit_msg>be more explicit in match for future-proofing code via exhaustiveness check<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ast::{Data, Container, Style};
use attr::{Identifier, EnumTag};
use Ctxt;

/// Cross-cutting checks that require looking at more than a single attrs
/// object. Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &Container) {
    check_getter(cx, cont);
    check_identifier(cx, cont);
    check_variant_skip_attrs(cx, cont);
    check_internally_tagged_variant_name_conflict(cx, cont);
}

/// Getters are only allowed inside structs (not enums) with the `remote`
/// attribute.
fn check_getter(cx: &Ctxt, cont: &Container) {
    match cont.data {
        Data::Enum(_) => {
            if cont.data.has_getter() {
                cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
            }
        }
        Data::Struct(_, _) => {
            if cont.data.has_getter() && cont.attrs.remote().is_none() {
                cx.error(
                    "#[serde(getter = \"...\")] can only be used in structs \
                     that have #[serde(remote = \"...\")]",
                );
            }
        }
    }
}

/// The `other` attribute must be used at most once and it must be the last
/// variant of an enum that has the `field_identifier` attribute.
///
/// Inside a `variant_identifier` all variants must be unit variants. Inside a
/// `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return;
        }
    };

    for (i, variant) in variants.iter().enumerate() {
        match (
            variant.style,
            cont.attrs.identifier(),
            variant.attrs.other(),
        ) {
            // The `other` attribute may only be used in a field_identifier.
            (_, Identifier::Variant, true) | (_, Identifier::No, true) => {
                cx.error("#[serde(other)] may only be used inside a field_identifier");
            }

            // Variant with `other` attribute must be the last one.
            (Style::Unit, Identifier::Field, true) => {
                if i < variants.len() - 1 {
                    cx.error("#[serde(other)] must be the last variant");
                }
            }

            // Variant with `other` attribute must be a unit variant.
            (_, Identifier::Field, true) => {
                cx.error("#[serde(other)] must be on a unit variant");
            }

            // Any sort of variant is allowed if this is not an identifier.
            (_, Identifier::No, false) => {}

            // Unit variant without `other` attribute is always fine.
            (Style::Unit, _, false) => {}

            // The last field is allowed to be a newtype catch-all.
            (Style::Newtype, Identifier::Field, false) => {
                if i < variants.len() - 1 {
                    cx.error(format!("`{}` must be the last variant", variant.ident));
                }
            }

            (_, Identifier::Field, false) => {
                cx.error("field_identifier may only contain unit variants");
            }

            (_, Identifier::Variant, false) => {
                cx.error("variant_identifier may only contain unit variants");
            }
        }
    }
}

/// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => {
            return;
        }
    };

    for variant in variants.iter() {
        if variant.attrs.serialize_with().is_some() {
            if variant.attrs.skip_serializing() {
                cx.error(format!(
                    "variant `{}` cannot have both #[serde(serialize_with)] and \
                     #[serde(skip_serializing)]",
                    variant.ident
                ));
            }

            for (i, field) in variant.fields.iter().enumerate() {
                let ident = field
                    .ident
                    .as_ref()
                    .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));

                if field.attrs.skip_serializing() {
                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(serialize_with)] and \
                         a field {} marked with #[serde(skip_serializing)]",
                        variant.ident, ident
                    ));
                }

                if field.attrs.skip_serializing_if().is_some() {
                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(serialize_with)] and \
                         a field {} marked with #[serde(skip_serializing_if)]",
                        variant.ident, ident
                    ));
                }
            }
        }

        if variant.attrs.deserialize_with().is_some() {
            if variant.attrs.skip_deserializing() {
                cx.error(format!(
                    "variant `{}` cannot have both #[serde(deserialize_with)] and \
                     #[serde(skip_deserializing)]",
                    variant.ident
                ));
            }

            for (i, field) in variant.fields.iter().enumerate() {
                if field.attrs.skip_deserializing() {
                    let ident = field
                        .ident
                        .as_ref()
                        .map_or_else(|| format!("{}", i), |ident| format!("`{}`", ident));

                    cx.error(format!(
                        "variant `{}` cannot have both #[serde(deserialize_with)] \
                         and a field {} marked with #[serde(skip_deserializing)]",
                        variant.ident, ident
                    ));
                }
            }
        }
    }
}

fn check_internally_tagged_variant_name_conflict(
    cx: &Ctxt,
    cont: &Container,
) {
    let variants = match cont.data {
        Data::Enum(ref variants) => variants,
        Data::Struct(_, _) => return,
    };

    let tag = match *cont.attrs.tag() {
        EnumTag::Internal { ref tag } => tag.as_str(),
        EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
    };

    let diagnose_conflict = || {
        let message = format!(
            "variant field name `{}` conflicts with internal tag",
            tag
        );
        cx.error(message);
    };

    for variant in variants {
        match variant.style {
            Style::Struct => {
                for field in &variant.fields {
                    let check_ser = !field.attrs.skip_serializing();
                    let check_de = !field.attrs.skip_deserializing();
                    let name = field.attrs.name();
                    let ser_name = name.serialize_name();
                    let de_name = name.deserialize_name();

                    if check_ser && ser_name == tag || check_de && de_name == tag {
                        diagnose_conflict();
                        return;
                    }
                }
            },
            Style::Unit | Style::Newtype | Style::Tuple => {},
        }
    }
}
<|endoftext|>


<commit_before>//! lint on manually implemented checked conversions that could be transformed into try_from

use if_chain::if_chain;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use syntax::ast::LitKind;

use crate::utils::{span_lint, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for explicit bounds checking when casting.
    ///
    /// **Why is this bad?** Reduces the readability of statements & is error prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let foo: u32 = 5;
    /// # let _ =
    /// foo <= i32::max_value() as u32
    /// # ;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # let _ =
    /// i32::try_from(foo).is_ok()
    /// # ;
    /// ```
    pub CHECKED_CONVERSIONS,
    pedantic,
    "`try_from` could replace manual bounds checking when casting"
}

declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, item: &Expr) {
        let result = if_chain! {
            if !in_external_macro(cx.sess(), item.span);
            if let ExprKind::Binary(op, ref left, ref right) = &item.node;

            then {
                match op.node {
                    BinOpKind::Ge | BinOpKind::Le => single_check(item),
                    BinOpKind::And => double_check(cx, left, right),
                    _ => None,
                }
            } else {
                None
            }
        };

        if let Some(cv) = result {
            span_lint(
                cx,
                CHECKED_CONVERSIONS,
                item.span,
                &format!(
                    "Checked cast can be simplified: `{}::try_from`",
                    cv.to_type.unwrap_or("IntegerType".to_string()),
                ),
            );
        }
    }
}

/// Searches for a single check from unsigned to _ is done
/// todo: check for case signed -> larger unsigned == only x >= 0
fn single_check(expr: &Expr) -> Option<Conversion<'_>> {
    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
}

/// Searches for a combination of upper & lower bound checks
fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr, right: &'a Expr) -> Option<Conversion<'a>> {
    let upper_lower = |l, r| {
        let upper = check_upper_bound(l);
        let lower = check_lower_bound(r);

        transpose(upper, lower).and_then(|(l, r)| l.combine(r, cx))
    };

    upper_lower(left, right).or_else(|| upper_lower(right, left))
}

/// Contains the result of a tried conversion check
#[derive(Clone, Debug)]
struct Conversion<'a> {
    cvt: ConversionType,
    expr_to_cast: &'a Expr,
    to_type: Option<String>,
}

/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
enum ConversionType {
    SignedToUnsigned,
    SignedToSigned,
    FromUnsigned,
}

impl<'a> Conversion<'a> {
    /// Combine multiple conversions if the are compatible
    pub fn combine(self, other: Self, cx: &LateContext<'_, '_>) -> Option<Conversion<'a>> {
        if self.is_compatible(&other, cx) {
            // Prefer a Conversion that contains a type-constraint
            Some(if self.to_type.is_some() { self } else { other })
        } else {
            None
        }
    }

    /// Checks if two conversions are compatible
    /// same type of conversion, same 'castee' and same 'to type'
    pub fn is_compatible(&self, other: &Self, cx: &LateContext<'_, '_>) -> bool {
        (self.cvt == other.cvt)
            && (SpanlessEq::new(cx).eq_expr(self.expr_to_cast, other.expr_to_cast))
            && (self.has_compatible_to_type(other))
    }

    /// Checks if the to-type is the same (if there is a type constraint)
    fn has_compatible_to_type(&self, other: &Self) -> bool {
        transpose(self.to_type.as_ref(), other.to_type.as_ref())
            .map(|(l, r)| l == r)
            .unwrap_or(true)
    }

    /// Try to construct a new conversion if the conversion type is valid
    fn try_new<'b>(expr_to_cast: &'a Expr, from_type: &'b str, to_type: String) -> Option<Conversion<'a>> {
        ConversionType::try_new(from_type, &to_type).map(|cvt| Conversion {
            cvt,
            expr_to_cast,
            to_type: Some(to_type),
        })
    }

    /// Construct a new conversion without type constraint
    fn new_any(expr_to_cast: &'a Expr) -> Conversion<'a> {
        Conversion {
            cvt: ConversionType::SignedToUnsigned,
            expr_to_cast,
            to_type: None,
        }
    }
}

impl ConversionType {
    /// Creates a conversion type if the type is allowed & conversion is valid
    fn try_new(from: &str, to: &str) -> Option<ConversionType> {
        if UNSIGNED_TYPES.contains(&from) {
            Some(ConversionType::FromUnsigned)
        } else if SIGNED_TYPES.contains(&from) {
            if UNSIGNED_TYPES.contains(&to) {
                Some(ConversionType::SignedToUnsigned)
            } else if SIGNED_TYPES.contains(&to) {
                Some(ConversionType::SignedToSigned)
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Check for `expr <= (to_type::max_value() as from_type)`
fn check_upper_bound(expr: &Expr) -> Option<Conversion<'_>> {
    if_chain! {
         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.node;
         if let Some((candidate, check)) = normalize_le_ge(op, left, right);
         if let Some((from, to)) = get_types_from_cast(check, "max_value", INT_TYPES);

         then {
             Conversion::try_new(candidate, &from, to)
         } else {
            None
        }
    }
}

/// Check for `expr >= 0|(to_type::min_value() as from_type)`
fn check_lower_bound(expr: &Expr) -> Option<Conversion<'_>> {
    fn check_function<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
    }

    // First of we need a binary containing the expression & the cast
    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.node {
        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
    } else {
        None
    }
}

/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
    if_chain! {
        if let ExprKind::Lit(ref lit) = &check.node;
        if let LitKind::Int(0, _) = &lit.node;

        then {
            Some(Conversion::new_any(candidate))
        } else {
            None
        }
    }
}

/// Check for `expr >= (to_type::min_value() as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
    if let Some((from, to)) = get_types_from_cast(check, "min_value", SIGNED_TYPES) {
        Conversion::try_new(candidate, &from, to)
    } else {
        None
    }
}

/// Tries to extract the from- and to-type from a cast expression
fn get_types_from_cast(expr: &Expr, func: &str, types: &[&str]) -> Option<(String, String)> {
    // `to_type::maxmin_value() as from_type`
    let call_from_cast: Option<(&Expr, String)> = if_chain! {
        // to_type::maxmin_value(), from_type
        if let ExprKind::Cast(ref limit, ref from_type) = &expr.node;
        if let TyKind::Path(ref from_type_path) = &from_type.node;
        if let Some(from_type_str) = int_ty_to_str(from_type_path);

        then {
            Some((limit, from_type_str.to_string()))
        } else {
            None
        }
    };

    // `from_type::from(to_type::maxmin_value())`
    let limit_from: Option<(&Expr, String)> = call_from_cast.or_else(|| {
        if_chain! {
            // `from_type::from, to_type::maxmin_value()`
            if let ExprKind::Call(ref from_func, ref args) = &expr.node;
            // `to_type::maxmin_value()`
            if args.len() == 1;
            if let limit = &args[0];
            // `from_type::from`
            if let ExprKind::Path(ref path) = &from_func.node;
            if let Some(from_type) = get_implementing_type(path, INT_TYPES, "from");

            then {
                Some((limit, from_type))
            } else {
                None
            }
        }
    });

    if let Some((limit, from_type)) = limit_from {
        if_chain! {
            if let ExprKind::Call(ref fun_name, _) = &limit.node;
            // `to_type, maxmin_value`
            if let ExprKind::Path(ref path) = &fun_name.node;
            // `to_type`
            if let Some(to_type) = get_implementing_type(path, types, func);

            then {
                Some((from_type, to_type))
            } else {
                None
            }
        }
    } else {
        None
    }
}

/// Gets the type which implements the called function
fn get_implementing_type(path: &QPath, candidates: &[&str], function: &str) -> Option<String> {
    if_chain! {
        if let QPath::TypeRelative(ref ty, ref path) = &path;
        if path.ident.name == function;
        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.node;
        if let [int] = &*tp.segments;
        let name = int.ident.as_str().get();
        if candidates.contains(&name);

        then {
            Some(name.to_string())
        } else {
            None
        }
    }
}

/// Gets the type as a string, if it is a supported integer
fn int_ty_to_str(path: &QPath) -> Option<&str> {
    if_chain! {
        if let QPath::Resolved(_, ref path) = *path;
        if let [ty] = &*path.segments;

        then {
            INT_TYPES
                .into_iter()
                .find(|c| (&ty.ident.name) == *c)
                .cloned()
        } else {
            None
        }
    }
}

/// (Option<T>, Option<U>) -> Option<(T, U)>
fn transpose<T, U>(lhs: Option<T>, rhs: Option<U>) -> Option<(T, U)> {
    match (lhs, rhs) {
        (Some(l), Some(r)) => Some((l, r)),
        _ => None,
    }
}

/// Will return the expressions as if they were expr1 <= expr2
fn normalize_le_ge<'a>(op: &'a BinOp, left: &'a Expr, right: &'a Expr) -> Option<(&'a Expr, &'a Expr)> {
    match op.node {
        BinOpKind::Le => Some((left, right)),
        BinOpKind::Ge => Some((right, left)),
        _ => None,
    }
}

const UNSIGNED_TYPES: &[&str] = &["u8", "u16", "u32", "u64", "u128", "usize"];
const SIGNED_TYPES: &[&str] = &["i8", "i16", "i32", "i64", "i128", "isize"];
const INT_TYPES: &[&str] = &[
    "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize",
];
<commit_msg>Fixed clippy lints in checked_conversions.rs.<commit_after>//! lint on manually implemented checked conversions that could be transformed into `try_from`

use if_chain::if_chain;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use syntax::ast::LitKind;

use crate::utils::{span_lint, SpanlessEq};

declare_clippy_lint! {
    /// **What it does:** Checks for explicit bounds checking when casting.
    ///
    /// **Why is this bad?** Reduces the readability of statements & is error prone.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// # let foo: u32 = 5;
    /// # let _ =
    /// foo <= i32::max_value() as u32
    /// # ;
    /// ```
    ///
    /// Could be written:
    ///
    /// ```rust
    /// # let _ =
    /// i32::try_from(foo).is_ok()
    /// # ;
    /// ```
    pub CHECKED_CONVERSIONS,
    pedantic,
    "`try_from` could replace manual bounds checking when casting"
}

declare_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
    fn check_expr(&mut self, cx: &LateContext<'_, '_>, item: &Expr) {
        let result = if_chain! {
            if !in_external_macro(cx.sess(), item.span);
            if let ExprKind::Binary(op, ref left, ref right) = &item.node;

            then {
                match op.node {
                    BinOpKind::Ge | BinOpKind::Le => single_check(item),
                    BinOpKind::And => double_check(cx, left, right),
                    _ => None,
                }
            } else {
                None
            }
        };

        if let Some(cv) = result {
            span_lint(
                cx,
                CHECKED_CONVERSIONS,
                item.span,
                &format!(
                    "Checked cast can be simplified: `{}::try_from`",
                    cv.to_type.unwrap_or_else(|| "IntegerType".to_string()),
                ),
            );
        }
    }
}

/// Searches for a single check from unsigned to _ is done
/// todo: check for case signed -> larger unsigned == only x >= 0
fn single_check(expr: &Expr) -> Option<Conversion<'_>> {
    check_upper_bound(expr).filter(|cv| cv.cvt == ConversionType::FromUnsigned)
}

/// Searches for a combination of upper & lower bound checks
fn double_check<'a>(cx: &LateContext<'_, '_>, left: &'a Expr, right: &'a Expr) -> Option<Conversion<'a>> {
    let upper_lower = |l, r| {
        let upper = check_upper_bound(l);
        let lower = check_lower_bound(r);

        transpose(upper, lower).and_then(|(l, r)| l.combine(r, cx))
    };

    upper_lower(left, right).or_else(|| upper_lower(right, left))
}

/// Contains the result of a tried conversion check
#[derive(Clone, Debug)]
struct Conversion<'a> {
    cvt: ConversionType,
    expr_to_cast: &'a Expr,
    to_type: Option<String>,
}

/// The kind of conversion that is checked
#[derive(Copy, Clone, Debug, PartialEq)]
enum ConversionType {
    SignedToUnsigned,
    SignedToSigned,
    FromUnsigned,
}

impl<'a> Conversion<'a> {
    /// Combine multiple conversions if the are compatible
    pub fn combine(self, other: Self, cx: &LateContext<'_, '_>) -> Option<Conversion<'a>> {
        if self.is_compatible(&other, cx) {
            // Prefer a Conversion that contains a type-constraint
            Some(if self.to_type.is_some() { self } else { other })
        } else {
            None
        }
    }

    /// Checks if two conversions are compatible
    /// same type of conversion, same 'castee' and same 'to type'
    pub fn is_compatible(&self, other: &Self, cx: &LateContext<'_, '_>) -> bool {
        (self.cvt == other.cvt)
            && (SpanlessEq::new(cx).eq_expr(self.expr_to_cast, other.expr_to_cast))
            && (self.has_compatible_to_type(other))
    }

    /// Checks if the to-type is the same (if there is a type constraint)
    fn has_compatible_to_type(&self, other: &Self) -> bool {
        transpose(self.to_type.as_ref(), other.to_type.as_ref())
            .map(|(l, r)| l == r)
            .unwrap_or(true)
    }

    /// Try to construct a new conversion if the conversion type is valid
    fn try_new<'b>(expr_to_cast: &'a Expr, from_type: &'b str, to_type: String) -> Option<Conversion<'a>> {
        ConversionType::try_new(from_type, &to_type).map(|cvt| Conversion {
            cvt,
            expr_to_cast,
            to_type: Some(to_type),
        })
    }

    /// Construct a new conversion without type constraint
    fn new_any(expr_to_cast: &'a Expr) -> Conversion<'a> {
        Conversion {
            cvt: ConversionType::SignedToUnsigned,
            expr_to_cast,
            to_type: None,
        }
    }
}

impl ConversionType {
    /// Creates a conversion type if the type is allowed & conversion is valid
    fn try_new(from: &str, to: &str) -> Option<ConversionType> {
        if UNSIGNED_TYPES.contains(&from) {
            Some(ConversionType::FromUnsigned)
        } else if SIGNED_TYPES.contains(&from) {
            if UNSIGNED_TYPES.contains(&to) {
                Some(ConversionType::SignedToUnsigned)
            } else if SIGNED_TYPES.contains(&to) {
                Some(ConversionType::SignedToSigned)
            } else {
                None
            }
        } else {
            None
        }
    }
}

/// Check for `expr <= (to_type::max_value() as from_type)`
fn check_upper_bound(expr: &Expr) -> Option<Conversion<'_>> {
    if_chain! {
         if let ExprKind::Binary(ref op, ref left, ref right) = &expr.node;
         if let Some((candidate, check)) = normalize_le_ge(op, left, right);
         if let Some((from, to)) = get_types_from_cast(check, "max_value", INT_TYPES);

         then {
             Conversion::try_new(candidate, &from, to)
         } else {
            None
        }
    }
}

/// Check for `expr >= 0|(to_type::min_value() as from_type)`
fn check_lower_bound(expr: &Expr) -> Option<Conversion<'_>> {
    fn check_function<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
        (check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
    }

    // First of we need a binary containing the expression & the cast
    if let ExprKind::Binary(ref op, ref left, ref right) = &expr.node {
        normalize_le_ge(op, right, left).and_then(|(l, r)| check_function(l, r))
    } else {
        None
    }
}

/// Check for `expr >= 0`
fn check_lower_bound_zero<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
    if_chain! {
        if let ExprKind::Lit(ref lit) = &check.node;
        if let LitKind::Int(0, _) = &lit.node;

        then {
            Some(Conversion::new_any(candidate))
        } else {
            None
        }
    }
}

/// Check for `expr >= (to_type::min_value() as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr, check: &'a Expr) -> Option<Conversion<'a>> {
    if let Some((from, to)) = get_types_from_cast(check, "min_value", SIGNED_TYPES) {
        Conversion::try_new(candidate, &from, to)
    } else {
        None
    }
}

/// Tries to extract the from- and to-type from a cast expression
fn get_types_from_cast(expr: &Expr, func: &str, types: &[&str]) -> Option<(String, String)> {
    // `to_type::maxmin_value() as from_type`
    let call_from_cast: Option<(&Expr, String)> = if_chain! {
        // to_type::maxmin_value(), from_type
        if let ExprKind::Cast(ref limit, ref from_type) = &expr.node;
        if let TyKind::Path(ref from_type_path) = &from_type.node;
        if let Some(from_type_str) = int_ty_to_str(from_type_path);

        then {
            Some((limit, from_type_str.to_string()))
        } else {
            None
        }
    };

    // `from_type::from(to_type::maxmin_value())`
    let limit_from: Option<(&Expr, String)> = call_from_cast.or_else(|| {
        if_chain! {
            // `from_type::from, to_type::maxmin_value()`
            if let ExprKind::Call(ref from_func, ref args) = &expr.node;
            // `to_type::maxmin_value()`
            if args.len() == 1;
            if let limit = &args[0];
            // `from_type::from`
            if let ExprKind::Path(ref path) = &from_func.node;
            if let Some(from_type) = get_implementing_type(path, INT_TYPES, "from");

            then {
                Some((limit, from_type))
            } else {
                None
            }
        }
    });

    if let Some((limit, from_type)) = limit_from {
        if_chain! {
            if let ExprKind::Call(ref fun_name, _) = &limit.node;
            // `to_type, maxmin_value`
            if let ExprKind::Path(ref path) = &fun_name.node;
            // `to_type`
            if let Some(to_type) = get_implementing_type(path, types, func);

            then {
                Some((from_type, to_type))
            } else {
                None
            }
        }
    } else {
        None
    }
}

/// Gets the type which implements the called function
fn get_implementing_type(path: &QPath, candidates: &[&str], function: &str) -> Option<String> {
    if_chain! {
        if let QPath::TypeRelative(ref ty, ref path) = &path;
        if path.ident.name == function;
        if let TyKind::Path(QPath::Resolved(None, ref tp)) = &ty.node;
        if let [int] = &*tp.segments;
        let name = int.ident.as_str().get();
        if candidates.contains(&name);

        then {
            Some(name.to_string())
        } else {
            None
        }
    }
}

/// Gets the type as a string, if it is a supported integer
fn int_ty_to_str(path: &QPath) -> Option<&str> {
    if_chain! {
        if let QPath::Resolved(_, ref path) = *path;
        if let [ty] = &*path.segments;

        then {
            INT_TYPES
                .iter()
                .find(|c| (&ty.ident.name) == *c)
                .cloned()
        } else {
            None
        }
    }
}

/// (Option<T>, Option<U>) -> Option<(T, U)>
fn transpose<T, U>(lhs: Option<T>, rhs: Option<U>) -> Option<(T, U)> {
    match (lhs, rhs) {
        (Some(l), Some(r)) => Some((l, r)),
        _ => None,
    }
}

/// Will return the expressions as if they were expr1 <= expr2
fn normalize_le_ge<'a>(op: &'a BinOp, left: &'a Expr, right: &'a Expr) -> Option<(&'a Expr, &'a Expr)> {
    match op.node {
        BinOpKind::Le => Some((left, right)),
        BinOpKind::Ge => Some((right, left)),
        _ => None,
    }
}

const UNSIGNED_TYPES: &[&str] = &["u8", "u16", "u32", "u64", "u128", "usize"];
const SIGNED_TYPES: &[&str] = &["i8", "i16", "i32", "i64", "i128", "isize"];
const INT_TYPES: &[&str] = &[
    "u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize",
];
<|endoftext|>


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

//! Utilities for tracing JS-managed values.
//!
//! The lifetime of DOM objects is managed by the SpiderMonkey Garbage
//! Collector. A rooted DOM object implementing the interface `Foo` is traced
//! as follows:
//!
//! 1. The GC calls `_trace` defined in `FooBinding` during the marking
//!    phase. (This happens through `JSClass.trace` for non-proxy bindings, and
//!    through `ProxyTraps.trace` otherwise.)
//! 2. `_trace` calls `Foo::trace()` (an implementation of `JSTraceable`).
//!     This is typically derived via a #[jstraceable] annotation
//! 3. For all fields (except those wrapped in `Untraceable`), `Foo::trace()`
//!    calls `trace()` on the field.
//!    For example, for fields of type `JS<T>`, `JS<T>::trace()` calls
//!    `trace_reflector()`.
//! 4. `trace_reflector()` calls `trace_object()` with the `JSObject` for the
//!    reflector.
//! 5. `trace_object()` calls `JS_CallTracer()` to notify the GC, which will
//!    add the object to the graph, and will trace that object as well.
//!
//! The untraceable!() macro adds an empty implementation of JSTraceable to
//! a datatype.

use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector};
use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT};
use js::jsval::JSVal;

use libc;
use std::rc::Rc;
use std::cell::{Cell, RefCell};

use url::Url;
use servo_util::atom::Atom;
use servo_util::namespace::Namespace;
use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData};
use net::image_cache_task::ImageCacheTask;
use script_traits::ScriptControlChan;
use std::collections::hashmap::HashMap;
use collections::hash::Hash;
use style::PropertyDeclarationBlock;

impl<T: Reflectable> JSTraceable for JS<T> {
    fn trace(&self, trc: *mut JSTracer) {
        trace_reflector(trc, "", self.reflector());
    }
}

untraceable!(Reflector)

/// A trait to allow tracing (only) DOM objects.
pub trait JSTraceable {
    fn trace(&self, trc: *mut JSTracer);
}

/// Trace a `JSVal`.
pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) {
    if !val.is_markable() {
        return;
    }

    unsafe {
        let name = description.to_c_str();
        (*tracer).debugPrinter = None;
        (*tracer).debugPrintIndex = -1;
        (*tracer).debugPrintArg = name.as_ptr() as *const libc::c_void;
        debug!("tracing value {:s}", description);
        JS_CallTracer(tracer, val.to_gcthing(), val.trace_kind());
    }
}

/// Trace the `JSObject` held by `reflector`.
#[allow(unrooted_must_root)]
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
    trace_object(tracer, description, reflector.get_jsobject())
}

/// Trace a `JSObject`.
pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: *mut JSObject) {
    unsafe {
        let name = description.to_c_str();
        (*tracer).debugPrinter = None;
        (*tracer).debugPrintIndex = -1;
        (*tracer).debugPrintArg = name.as_ptr() as *const libc::c_void;
        debug!("tracing {:s}", description);
        JS_CallTracer(tracer, obj as *mut libc::c_void, JSTRACE_OBJECT);
    }
}

/// Encapsulates a type that cannot easily have `Encodable` derived automagically,
/// but also does not need to be made known to the SpiderMonkey garbage collector.
///
/// Use only with types that are not associated with a JS reflector and do not contain
/// fields of types associated with JS reflectors.
///
/// This should really only be used for types that are from other crates,
/// so we can't implement `Encodable`. See more details: mozilla#2662.
pub struct Untraceable<T> {
    inner: T,
}

impl<T> Untraceable<T> {
    pub fn new(val: T) -> Untraceable<T> {
        Untraceable {
            inner: val
        }
    }
}

impl<T> Deref<T> for Untraceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Untraceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

/// Encapsulates a type that can be traced but is boxed in a type we don't
/// control (such as `RefCell`).
///
/// Wrap a field in Traceable and implement the `Encodable` trait
/// for that new concrete type to achieve magic compiler-derived trace hooks.
///
/// We always prefer this, in case the contained type ever changes to something that should be traced.
/// See more details: mozilla#2662.
#[deriving(PartialEq, Clone)]
pub struct Traceable<T> {
    inner: T
}

impl<T> Traceable<T> {
    pub fn new(val: T) -> Traceable<T> {
        Traceable {
            inner: val
        }
    }
}

impl<T> Deref<T> for Traceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T: JSTraceable> JSTraceable for RefCell<T> {
    fn trace(&self, trc: *mut JSTracer) {
        self.borrow().trace(trc)
    }
}

impl<T: JSTraceable> JSTraceable for Rc<T> {
    fn trace(&self, trc: *mut JSTracer) {
        self.deref().trace(trc)
    }
}

impl<T: JSTraceable> JSTraceable for Box<T> {
    fn trace(&self, trc: *mut JSTracer) {
        (**self).trace(trc)
    }
}

impl<T: JSTraceable+Copy> JSTraceable for Traceable<Cell<T>> {
    fn trace(&self, trc: *mut JSTracer) {
        self.deref().get().trace(trc)
    }
}

impl<T: JSTraceable+Copy> JSTraceable for Cell<T> {
    fn trace(&self, trc: *mut JSTracer) {
        self.get().trace(trc)
    }
}

impl JSTraceable for Traceable<*mut JSObject> {
    fn trace(&self, trc: *mut JSTracer) {
        trace_object(trc, "object", **self);
    }
}

impl JSTraceable for Traceable<JSVal> {
    fn trace(&self, trc: *mut JSTracer) {
        trace_jsval(trc, "val", **self);
    }
}

// XXXManishearth Check if the following three are optimized to no-ops
// if e.trace() is a no-op (e.g it is an untraceable type)
impl<T: JSTraceable> JSTraceable for Vec<T> {
    #[inline]
    fn trace(&self, trc: *mut JSTracer) {
        for e in self.iter() {
            e.trace(trc);
        }
    }
}

impl<T: JSTraceable> JSTraceable for Option<T> {
    #[inline]
    fn trace(&self, trc: *mut JSTracer) {
        self.as_ref().map(|e| e.trace(trc));
    }
}

impl<K: Eq+Hash, V: JSTraceable> JSTraceable for HashMap<K, V> {
    #[inline]
    fn trace(&self, trc: *mut JSTracer) {
        for e in self.iter() {
            e.val1().trace(trc);
        }
    }
}

untraceable!(bool, f32, f64, String, Url)
untraceable!(uint, u8, u16, u32, u64)
untraceable!(int, i8, i16, i32, i64)
untraceable!(Untraceable<T>)
untraceable!(ImageCacheTask, ScriptControlChan)
untraceable!(Atom, Namespace)
untraceable!(PropertyDeclarationBlock)
// These three are interdependent, if you plan to put jsmanaged data
// in one of these make sure it is propagated properly to containing structs
untraceable!(SubpageId, WindowSizeData, PipelineId)

impl<'a> JSTraceable for &'a str {
    #[inline]
    fn trace(&self, _: *mut JSTracer) {
        // Do nothing
    }
}

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

//! Utilities for tracing JS-managed values.
//!
//! The lifetime of DOM objects is managed by the SpiderMonkey Garbage
//! Collector. A rooted DOM object implementing the interface `Foo` is traced
//! as follows:
//!
//! 1. The GC calls `_trace` defined in `FooBinding` during the marking
//!    phase. (This happens through `JSClass.trace` for non-proxy bindings, and
//!    through `ProxyTraps.trace` otherwise.)
//! 2. `_trace` calls `Foo::trace()` (an implementation of `JSTraceable`).
//!     This is typically derived via a #[jstraceable] annotation
//! 3. For all fields (except those wrapped in `Untraceable`), `Foo::trace()`
//!    calls `trace()` on the field.
//!    For example, for fields of type `JS<T>`, `JS<T>::trace()` calls
//!    `trace_reflector()`.
//! 4. `trace_reflector()` calls `trace_object()` with the `JSObject` for the
//!    reflector.
//! 5. `trace_object()` calls `JS_CallTracer()` to notify the GC, which will
//!    add the object to the graph, and will trace that object as well.
//!
//! The untraceable!() macro adds an empty implementation of JSTraceable to
//! a datatype.

use dom::bindings::js::JS;
use dom::bindings::utils::{Reflectable, Reflector};
use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT};
use js::jsval::JSVal;

use libc;
use std::rc::Rc;
use std::cell::{Cell, RefCell};

use url::Url;
use servo_util::atom::Atom;
use servo_util::namespace::Namespace;
use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData};
use net::image_cache_task::ImageCacheTask;
use script_traits::ScriptControlChan;
use std::collections::hashmap::HashMap;
use collections::hash::Hash;
use style::PropertyDeclarationBlock;

impl<T: Reflectable> JSTraceable for JS<T> {
    fn trace(&self, trc: *mut JSTracer) {
        trace_reflector(trc, "", self.reflector());
    }
}

untraceable!(Reflector)

/// A trait to allow tracing (only) DOM objects.
pub trait JSTraceable {
    fn trace(&self, trc: *mut JSTracer);
}

/// Trace a `JSVal`.
pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) {
    if !val.is_markable() {
        return;
    }

    unsafe {
        let name = description.to_c_str();
        (*tracer).debugPrinter = None;
        (*tracer).debugPrintIndex = -1;
        (*tracer).debugPrintArg = name.as_ptr() as *const libc::c_void;
        debug!("tracing value {:s}", description);
        JS_CallTracer(tracer, val.to_gcthing(), val.trace_kind());
    }
}

/// Trace the `JSObject` held by `reflector`.
#[allow(unrooted_must_root)]
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
    trace_object(tracer, description, reflector.get_jsobject())
}

/// Trace a `JSObject`.
pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: *mut JSObject) {
    unsafe {
        let name = description.to_c_str();
        (*tracer).debugPrinter = None;
        (*tracer).debugPrintIndex = -1;
        (*tracer).debugPrintArg = name.as_ptr() as *const libc::c_void;
        debug!("tracing {:s}", description);
        JS_CallTracer(tracer, obj as *mut libc::c_void, JSTRACE_OBJECT);
    }
}

/// Encapsulates a type that cannot easily have `Encodable` derived automagically,
/// but also does not need to be made known to the SpiderMonkey garbage collector.
///
/// Use only with types that are not associated with a JS reflector and do not contain
/// fields of types associated with JS reflectors.
///
/// This should really only be used for types that are from other crates,
/// so we can't implement `Encodable`. See more details: mozilla#2662.
pub struct Untraceable<T> {
    inner: T,
}

impl<T> Untraceable<T> {
    pub fn new(val: T) -> Untraceable<T> {
        Untraceable {
            inner: val
        }
    }
}

impl<T> Deref<T> for Untraceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T> DerefMut<T> for Untraceable<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.inner
    }
}

/// Encapsulates a type that can be traced but is boxed in a type we don't
/// control (such as `RefCell`).
///
/// Wrap a field in Traceable and implement the `Encodable` trait
/// for that new concrete type to achieve magic compiler-derived trace hooks.
///
/// We always prefer this, in case the contained type ever changes to something that should be traced.
/// See more details: mozilla#2662.
#[deriving(PartialEq, Clone)]
pub struct Traceable<T> {
    inner: T
}

impl<T> Traceable<T> {
    pub fn new(val: T) -> Traceable<T> {
        Traceable {
            inner: val
        }
    }
}

impl<T> Deref<T> for Traceable<T> {
    fn deref<'a>(&'a self) -> &'a T {
        &self.inner
    }
}

impl<T: JSTraceable> JSTraceable for RefCell<T> {
    fn trace(&self, trc: *mut JSTracer) {
        self.borrow().trace(trc)
    }
}

impl<T: JSTraceable> JSTraceable for Rc<T> {
    fn trace(&self, trc: *mut JSTracer) {
        self.deref().trace(trc)
    }
}

impl<T: JSTraceable> JSTraceable for Box<T> {
    fn trace(&self, trc: *mut JSTracer) {
        (**self).trace(trc)
    }
}

impl<T: JSTraceable+Copy> JSTraceable for Traceable<Cell<T>> {
    fn trace(&self, trc: *mut JSTracer) {
        self.deref().get().trace(trc)
    }
}

impl<T: JSTraceable+Copy> JSTraceable for Cell<T> {
    fn trace(&self, trc: *mut JSTracer) {
        self.get().trace(trc)
    }
}

impl JSTraceable for Traceable<*mut JSObject> {
    fn trace(&self, trc: *mut JSTracer) {
        trace_object(trc, "object", **self);
    }
}

impl JSTraceable for Traceable<JSVal> {
    fn trace(&self, trc: *mut JSTracer) {
        trace_jsval(trc, "val", **self);
    }
}

// XXXManishearth Check if the following three are optimized to no-ops
// if e.trace() is a no-op (e.g it is an untraceable type)
impl<T: JSTraceable> JSTraceable for Vec<T> {
    #[inline]
    fn trace(&self, trc: *mut JSTracer) {
        for e in self.iter() {
            e.trace(trc);
        }
    }
}

impl<T: JSTraceable> JSTraceable for Option<T> {
    #[inline]
    fn trace(&self, trc: *mut JSTracer) {
        self.as_ref().map(|e| e.trace(trc));
    }
}

impl<K: Eq+Hash+JSTraceable, V: JSTraceable> JSTraceable for HashMap<K, V> {
    #[inline]
    fn trace(&self, trc: *mut JSTracer) {
        for e in self.iter() {
            e.val0().trace(trc);
            e.val1().trace(trc);
        }
    }
}

untraceable!(bool, f32, f64, String, Url)
untraceable!(uint, u8, u16, u32, u64)
untraceable!(int, i8, i16, i32, i64)
untraceable!(Untraceable<T>)
untraceable!(ImageCacheTask, ScriptControlChan)
untraceable!(Atom, Namespace)
untraceable!(PropertyDeclarationBlock)
// These three are interdependent, if you plan to put jsmanaged data
// in one of these make sure it is propagated properly to containing structs
untraceable!(SubpageId, WindowSizeData, PipelineId)

impl<'a> JSTraceable for &'a str {
    #[inline]
    fn trace(&self, _: *mut JSTracer) {
        // Do nothing
    }
}

<|endoftext|>