<commit_before>#[doc = "Operations and constants for `float`"];

// Even though this module exports everything defined in it,
// because it contains re-exports, we also have to explicitly
// export locally defined things. That's a bit annoying.
export to_str_common, to_str_exact, to_str, from_str;
export add, sub, mul, div, rem, lt, le, gt, eq, eq, ne;
export is_positive, is_negative, is_nonpositive, is_nonnegative;
export is_zero, is_infinite, is_finite;
export NaN, is_NaN, infinity, neg_infinity;
export consts;
export logarithm;
export acos, asin, atan, atan2, cbrt, ceil, copysign, cos, cosh, floor;
export erf, erfc, exp, expm1, exp2, abs, abs_sub;
export mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp;
export lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix;
export modf, pow, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc;
export signbit;
export pow_with_uint;

// export when m_float == c_double

export j0, j1, jn, y0, y1, yn;

// PORT this must match in width according to architecture

import m_float = f64;
import f64::*;

/**
 * Section: String Conversions
 */

#[doc = "
Converts a float to a string

# Arguments

* num - The float value
* digits - The number of significant digits
* exact - Whether to enforce the exact number of significant digits
"]
fn to_str_common(num: float, digits: uint, exact: bool) -> str {
    if is_NaN(num) { ret "NaN"; }
    if num == infinity { ret "inf"; }
    if num == neg_infinity { ret "-inf"; }
    let mut (num, accum) = if num < 0.0 { (-num, "-") } else { (num, "") };
    let trunc = num as uint;
    let mut frac = num - (trunc as float);
    accum += uint::str(trunc);
    if (frac < epsilon && !exact) || digits == 0u { ret accum; }
    accum += ".";
    let mut i = digits;
    let mut epsilon = 1. / pow_with_uint(10u, i);
    while i > 0u && (frac >= epsilon || exact) {
        frac *= 10.0;
        epsilon *= 10.0;
        let digit = frac as uint;
        accum += uint::str(digit);
        frac -= digit as float;
        i -= 1u;
    }
    ret accum;

}

#[doc = "
Converts a float to a string with exactly the number of
provided significant digits

# Arguments

* num - The float value
* digits - The number of significant digits
"]
fn to_str_exact(num: float, digits: uint) -> str {
    to_str_common(num, digits, true)
}

#[test]
fn test_to_str_exact_do_decimal() {
    let s = to_str_exact(5.0, 4u);
    assert s == "5.0000";
}

#[doc = "
Converts a float to a string with a maximum number of
significant digits

# Arguments

* num - The float value
* digits - The number of significant digits
"]
fn to_str(num: float, digits: uint) -> str {
    to_str_common(num, digits, false)
}

#[doc = "
Convert a string to a float

This function accepts strings such as

* '3.14'
* '+3.14', equivalent to '3.14'
* '-3.14'
* '2.5E10', or equivalently, '2.5e10'
* '2.5E-10'
* '', or, equivalently, '.' (understood as 0)
* '5.'
* '.5', or, equivalently,  '0.5'

Leading and trailing whitespace are ignored.

# Arguments

* num - A string

# Return value

`none` if the string did not represent a valid number.  Otherwise, `some(n)`
where `n` is the floating-point number represented by `[num]`.
"]
fn from_str(num: str) -> option<float> {
   let mut pos = 0u;               //Current byte position in the string.
                                   //Used to walk the string in O(n).
   let len = str::len(num);        //Length of the string, in bytes.

   if len == 0u { ret none; }
   let mut total = 0f;             //Accumulated result
   let mut c     = 'z';            //Latest char.

   //The string must start with one of the following characters.
   alt str::char_at(num, 0u) {
      '-' | '+' | '0' to '9' | '.' {}
      _ { ret none; }
   }

   //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly.
   let mut neg = false;               //Sign of the result
   alt str::char_at(num, 0u) {
      '-' {
          neg = true;
          pos = 1u;
      }
      '+' {
          pos = 1u;
      }
      _ {}
   }

   //Examine the following chars until '.', 'e', 'E'
   while(pos < len) {
       let char_range = str::char_range_at(num, pos);
       c   = char_range.ch;
       pos = char_range.next;
       alt c {
         '0' to '9' {
           total = total * 10f;
           total += ((c as int) - ('0' as int)) as float;
         }
         '.' | 'e' | 'E' {
           break;
         }
         _ {
           ret none;
         }
       }
   }

   if c == '.' {//Examine decimal part
      let mut decimal = 1f;
      while(pos < len) {
         let char_range = str::char_range_at(num, pos);
         c = char_range.ch;
         pos = char_range.next;
         alt c {
            '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9'  {
                 decimal /= 10f;
                 total += (((c as int) - ('0' as int)) as float)*decimal;
             }
             'e' | 'E' {
                 break;
             }
             _ {
                 ret none;
             }
         }
      }
   }

   if (c == 'e') | (c == 'E') {//Examine exponent
      let mut exponent = 0u;
      let mut neg_exponent = false;
      if(pos < len) {
          let char_range = str::char_range_at(num, pos);
          c   = char_range.ch;
          alt c  {
             '+' {
                pos = char_range.next;
             }
             '-' {
                pos = char_range.next;
                neg_exponent = true;
             }
             _ {}
          }
          while(pos < len) {
             let char_range = str::char_range_at(num, pos);
             c = char_range.ch;
             alt c {
                 '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' {
                     exponent *= 10u;
                     exponent += ((c as uint) - ('0' as uint));
                 }
                 _ {
                     break;
                 }
             }
             pos = char_range.next;
          }
          let multiplier = pow_with_uint(10u, exponent);
              //Note: not [int::pow], otherwise, we'll quickly
              //end up with a nice overflow
          if neg_exponent {
             total = total / multiplier;
          } else {
             total = total * multiplier;
          }
      } else {
         ret none;
      }
   }

   if(pos < len) {
     ret none;
   } else {
     if(neg) {
        total *= -1f;
     }
     ret some(total);
   }
}

/**
 * Section: Arithmetics
 */

#[doc = "
Compute the exponentiation of an integer by another integer as a float

# Arguments

* x - The base
* pow - The exponent

# Return value

`NaN` if both `x` and `pow` are `0u`, otherwise `x^pow`
"]
fn pow_with_uint(base: uint, pow: uint) -> float {
   if base == 0u {
      if pow == 0u {
        ret NaN;
      }
       ret 0.;
   }
   let mut my_pow     = pow;
   let mut total      = 1f;
   let mut multiplier = base as float;
   while (my_pow > 0u) {
     if my_pow % 2u == 1u {
       total = total * multiplier;
     }
     my_pow     /= 2u;
     multiplier *= multiplier;
   }
   ret total;
}

#[test]
fn test_from_str() {
   assert from_str("3") == some(3.);
   assert from_str("3") == some(3.);
   assert from_str("3.14") == some(3.14);
   assert from_str("+3.14") == some(3.14);
   assert from_str("-3.14") == some(-3.14);
   assert from_str("2.5E10") == some(25000000000.);
   assert from_str("2.5e10") == some(25000000000.);
   assert from_str("25000000000.E-10") == some(2.5);
   assert from_str(".") == some(0.);
   assert from_str(".e1") == some(0.);
   assert from_str(".e-1") == some(0.);
   assert from_str("5.") == some(5.);
   assert from_str(".5") == some(0.5);
   assert from_str("0.5") == some(0.5);
   assert from_str("0.5") == some(0.5);
   assert from_str("0.5") == some(0.5);
   assert from_str("-.5") == some(-0.5);
   assert from_str("-.5") == some(-0.5);
   assert from_str("-5") == some(-5.);

   assert from_str("") == none;
   assert from_str("x") == none;
   assert from_str(" ") == none;
   assert from_str("   ") == none;
   assert from_str("e") == none;
   assert from_str("E") == none;
   assert from_str("E1") == none;
   assert from_str("1e1e1") == none;
   assert from_str("1e1.1") == none;
   assert from_str("1e1-1") == none;
}

#[test]
fn test_positive() {
  assert(is_positive(infinity));
  assert(is_positive(1.));
  assert(is_positive(0.));
  assert(!is_positive(-1.));
  assert(!is_positive(neg_infinity));
  assert(!is_positive(1./neg_infinity));
  assert(!is_positive(NaN));
}

#[test]
fn test_negative() {
  assert(!is_negative(infinity));
  assert(!is_negative(1.));
  assert(!is_negative(0.));
  assert(is_negative(-1.));
  assert(is_negative(neg_infinity));
  assert(is_negative(1./neg_infinity));
  assert(!is_negative(NaN));
}

#[test]
fn test_nonpositive() {
  assert(!is_nonpositive(infinity));
  assert(!is_nonpositive(1.));
  assert(!is_nonpositive(0.));
  assert(is_nonpositive(-1.));
  assert(is_nonpositive(neg_infinity));
  assert(is_nonpositive(1./neg_infinity));
  assert(!is_nonpositive(NaN));
}

#[test]
fn test_nonnegative() {
  assert(is_nonnegative(infinity));
  assert(is_nonnegative(1.));
  assert(is_nonnegative(0.));
  assert(!is_nonnegative(-1.));
  assert(!is_nonnegative(neg_infinity));
  assert(!is_nonnegative(1./neg_infinity));
  assert(!is_nonnegative(NaN));
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

<commit_msg>core: Add tests for the string repr of infinity<commit_after>#[doc = "Operations and constants for `float`"];

// Even though this module exports everything defined in it,
// because it contains re-exports, we also have to explicitly
// export locally defined things. That's a bit annoying.
export to_str_common, to_str_exact, to_str, from_str;
export add, sub, mul, div, rem, lt, le, gt, eq, eq, ne;
export is_positive, is_negative, is_nonpositive, is_nonnegative;
export is_zero, is_infinite, is_finite;
export NaN, is_NaN, infinity, neg_infinity;
export consts;
export logarithm;
export acos, asin, atan, atan2, cbrt, ceil, copysign, cos, cosh, floor;
export erf, erfc, exp, expm1, exp2, abs, abs_sub;
export mul_add, fmax, fmin, nextafter, frexp, hypot, ldexp;
export lgamma, ln, log_radix, ln1p, log10, log2, ilog_radix;
export modf, pow, round, sin, sinh, sqrt, tan, tanh, tgamma, trunc;
export signbit;
export pow_with_uint;

// export when m_float == c_double

export j0, j1, jn, y0, y1, yn;

// PORT this must match in width according to architecture

import m_float = f64;
import f64::*;

/**
 * Section: String Conversions
 */

#[doc = "
Converts a float to a string

# Arguments

* num - The float value
* digits - The number of significant digits
* exact - Whether to enforce the exact number of significant digits
"]
fn to_str_common(num: float, digits: uint, exact: bool) -> str {
    if is_NaN(num) { ret "NaN"; }
    if num == infinity { ret "inf"; }
    if num == neg_infinity { ret "-inf"; }
    let mut (num, accum) = if num < 0.0 { (-num, "-") } else { (num, "") };
    let trunc = num as uint;
    let mut frac = num - (trunc as float);
    accum += uint::str(trunc);
    if (frac < epsilon && !exact) || digits == 0u { ret accum; }
    accum += ".";
    let mut i = digits;
    let mut epsilon = 1. / pow_with_uint(10u, i);
    while i > 0u && (frac >= epsilon || exact) {
        frac *= 10.0;
        epsilon *= 10.0;
        let digit = frac as uint;
        accum += uint::str(digit);
        frac -= digit as float;
        i -= 1u;
    }
    ret accum;

}

#[doc = "
Converts a float to a string with exactly the number of
provided significant digits

# Arguments

* num - The float value
* digits - The number of significant digits
"]
fn to_str_exact(num: float, digits: uint) -> str {
    to_str_common(num, digits, true)
}

#[test]
fn test_to_str_exact_do_decimal() {
    let s = to_str_exact(5.0, 4u);
    assert s == "5.0000";
}

#[doc = "
Converts a float to a string with a maximum number of
significant digits

# Arguments

* num - The float value
* digits - The number of significant digits
"]
fn to_str(num: float, digits: uint) -> str {
    to_str_common(num, digits, false)
}

#[doc = "
Convert a string to a float

This function accepts strings such as

* '3.14'
* '+3.14', equivalent to '3.14'
* '-3.14'
* '2.5E10', or equivalently, '2.5e10'
* '2.5E-10'
* '', or, equivalently, '.' (understood as 0)
* '5.'
* '.5', or, equivalently,  '0.5'

Leading and trailing whitespace are ignored.

# Arguments

* num - A string

# Return value

`none` if the string did not represent a valid number.  Otherwise, `some(n)`
where `n` is the floating-point number represented by `[num]`.
"]
fn from_str(num: str) -> option<float> {
   let mut pos = 0u;               //Current byte position in the string.
                                   //Used to walk the string in O(n).
   let len = str::len(num);        //Length of the string, in bytes.

   if len == 0u { ret none; }
   let mut total = 0f;             //Accumulated result
   let mut c     = 'z';            //Latest char.

   //The string must start with one of the following characters.
   alt str::char_at(num, 0u) {
      '-' | '+' | '0' to '9' | '.' {}
      _ { ret none; }
   }

   //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly.
   let mut neg = false;               //Sign of the result
   alt str::char_at(num, 0u) {
      '-' {
          neg = true;
          pos = 1u;
      }
      '+' {
          pos = 1u;
      }
      _ {}
   }

   //Examine the following chars until '.', 'e', 'E'
   while(pos < len) {
       let char_range = str::char_range_at(num, pos);
       c   = char_range.ch;
       pos = char_range.next;
       alt c {
         '0' to '9' {
           total = total * 10f;
           total += ((c as int) - ('0' as int)) as float;
         }
         '.' | 'e' | 'E' {
           break;
         }
         _ {
           ret none;
         }
       }
   }

   if c == '.' {//Examine decimal part
      let mut decimal = 1f;
      while(pos < len) {
         let char_range = str::char_range_at(num, pos);
         c = char_range.ch;
         pos = char_range.next;
         alt c {
            '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9'  {
                 decimal /= 10f;
                 total += (((c as int) - ('0' as int)) as float)*decimal;
             }
             'e' | 'E' {
                 break;
             }
             _ {
                 ret none;
             }
         }
      }
   }

   if (c == 'e') | (c == 'E') {//Examine exponent
      let mut exponent = 0u;
      let mut neg_exponent = false;
      if(pos < len) {
          let char_range = str::char_range_at(num, pos);
          c   = char_range.ch;
          alt c  {
             '+' {
                pos = char_range.next;
             }
             '-' {
                pos = char_range.next;
                neg_exponent = true;
             }
             _ {}
          }
          while(pos < len) {
             let char_range = str::char_range_at(num, pos);
             c = char_range.ch;
             alt c {
                 '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' {
                     exponent *= 10u;
                     exponent += ((c as uint) - ('0' as uint));
                 }
                 _ {
                     break;
                 }
             }
             pos = char_range.next;
          }
          let multiplier = pow_with_uint(10u, exponent);
              //Note: not [int::pow], otherwise, we'll quickly
              //end up with a nice overflow
          if neg_exponent {
             total = total / multiplier;
          } else {
             total = total * multiplier;
          }
      } else {
         ret none;
      }
   }

   if(pos < len) {
     ret none;
   } else {
     if(neg) {
        total *= -1f;
     }
     ret some(total);
   }
}

/**
 * Section: Arithmetics
 */

#[doc = "
Compute the exponentiation of an integer by another integer as a float

# Arguments

* x - The base
* pow - The exponent

# Return value

`NaN` if both `x` and `pow` are `0u`, otherwise `x^pow`
"]
fn pow_with_uint(base: uint, pow: uint) -> float {
   if base == 0u {
      if pow == 0u {
        ret NaN;
      }
       ret 0.;
   }
   let mut my_pow     = pow;
   let mut total      = 1f;
   let mut multiplier = base as float;
   while (my_pow > 0u) {
     if my_pow % 2u == 1u {
       total = total * multiplier;
     }
     my_pow     /= 2u;
     multiplier *= multiplier;
   }
   ret total;
}

#[test]
fn test_from_str() {
   assert from_str("3") == some(3.);
   assert from_str("3") == some(3.);
   assert from_str("3.14") == some(3.14);
   assert from_str("+3.14") == some(3.14);
   assert from_str("-3.14") == some(-3.14);
   assert from_str("2.5E10") == some(25000000000.);
   assert from_str("2.5e10") == some(25000000000.);
   assert from_str("25000000000.E-10") == some(2.5);
   assert from_str(".") == some(0.);
   assert from_str(".e1") == some(0.);
   assert from_str(".e-1") == some(0.);
   assert from_str("5.") == some(5.);
   assert from_str(".5") == some(0.5);
   assert from_str("0.5") == some(0.5);
   assert from_str("0.5") == some(0.5);
   assert from_str("0.5") == some(0.5);
   assert from_str("-.5") == some(-0.5);
   assert from_str("-.5") == some(-0.5);
   assert from_str("-5") == some(-5.);

   assert from_str("") == none;
   assert from_str("x") == none;
   assert from_str(" ") == none;
   assert from_str("   ") == none;
   assert from_str("e") == none;
   assert from_str("E") == none;
   assert from_str("E1") == none;
   assert from_str("1e1e1") == none;
   assert from_str("1e1.1") == none;
   assert from_str("1e1-1") == none;
}

#[test]
fn test_positive() {
  assert(is_positive(infinity));
  assert(is_positive(1.));
  assert(is_positive(0.));
  assert(!is_positive(-1.));
  assert(!is_positive(neg_infinity));
  assert(!is_positive(1./neg_infinity));
  assert(!is_positive(NaN));
}

#[test]
fn test_negative() {
  assert(!is_negative(infinity));
  assert(!is_negative(1.));
  assert(!is_negative(0.));
  assert(is_negative(-1.));
  assert(is_negative(neg_infinity));
  assert(is_negative(1./neg_infinity));
  assert(!is_negative(NaN));
}

#[test]
fn test_nonpositive() {
  assert(!is_nonpositive(infinity));
  assert(!is_nonpositive(1.));
  assert(!is_nonpositive(0.));
  assert(is_nonpositive(-1.));
  assert(is_nonpositive(neg_infinity));
  assert(is_nonpositive(1./neg_infinity));
  assert(!is_nonpositive(NaN));
}

#[test]
fn test_nonnegative() {
  assert(is_nonnegative(infinity));
  assert(is_nonnegative(1.));
  assert(is_nonnegative(0.));
  assert(!is_nonnegative(-1.));
  assert(!is_nonnegative(neg_infinity));
  assert(!is_nonnegative(1./neg_infinity));
  assert(!is_nonnegative(NaN));
}

#[test]
fn test_to_str_inf() {
    assert to_str(infinity, 10u) == "inf";
    assert to_str(-infinity, 10u) == "-inf";
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//

<|endoftext|>


<commit_before>use std::default::Default;
use std::path::Path;

use collada;
use gfx;
use gfx::traits::*;
use gfx_texture;

use math::*;
use skeleton::Skeleton;

const MAX_JOINTS: usize = 64;

pub struct SkinnedRenderBatch<R: gfx::Resources> {
    skinning_transforms_buffer: gfx::BufferHandle<R, [[f32; 4]; 4]>,
    batch: gfx::batch::RefBatch<SkinnedShaderParams<R>>,
}

pub struct SkinnedRenderer<R: gfx::Resources> {
    skeleton: Skeleton, // TODO Should this be a ref? Should this just be the joints?
    render_batches: Vec<SkinnedRenderBatch<R>>,
}

impl<R: gfx::Resources> SkinnedRenderer<R> {

    pub fn from_collada<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        D: Device<Resources = R, CommandBuffer = C>,
    > (
        graphics: &mut gfx::Graphics<D, F>,
        collada_document: collada::document::ColladaDocument,
        texture_paths: Vec<&str>, // TODO - read from the COLLADA document (if available)
    ) -> Result<SkinnedRenderer<R>, gfx::ProgramError> {

        let program = match graphics.factory.link_program(SKINNED_VERTEX_SHADER.clone(), SKINNED_FRAGMENT_SHADER.clone()) {
            Ok(program_handle) => program_handle,
            Err(e) => return Err(e),
        };

        let obj_set = collada_document.get_obj_set().unwrap();

        let mut skeleton_set = collada_document.get_skeletons().unwrap();
        let mut animations = collada_document.get_animations();
        let skeleton = Skeleton::from_collada(&skeleton_set[0]);

        let mut render_batches = Vec::new();

        for (i, object) in obj_set.objects.iter().enumerate().take(6) {

            let mut vertex_data: Vec<SkinnedVertex> = Vec::new();
            let mut index_data: Vec<u32> = Vec::new();

            get_vertex_index_data(&object, &mut vertex_data, &mut index_data);

            let mesh = graphics.factory.create_mesh(vertex_data.as_slice());

            let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

            let slice = graphics.factory
                .create_buffer_index::<u32>(index_data.as_slice())
                .to_slice(gfx::PrimitiveType::TriangleList);

            let skinning_transforms_buffer = graphics.factory.create_buffer::<[[f32; 4]; 4]>(MAX_JOINTS, gfx::BufferUsage::Dynamic);

            let texture = gfx_texture::Texture::from_path(
                &mut graphics.factory,
                &Path::new(&texture_paths[i]),
                &gfx_texture::Settings::new()
            ).unwrap();

            let sampler = graphics.factory.create_sampler(
                gfx::tex::SamplerInfo::new(
                    gfx::tex::FilterMethod::Trilinear,
                    gfx::tex::WrapMode::Clamp
                    )
                );

            let shader_params = SkinnedShaderParams {
                u_model_view_proj: mat4_id(),
                u_model_view: mat4_id(),
                u_skinning_transforms: skinning_transforms_buffer.raw().clone(),
                u_texture: (texture.handle, Some(sampler)),
            };

            let batch: gfx::batch::RefBatch<SkinnedShaderParams<R>> = graphics.make_batch(&program, shader_params, &mesh, slice, &state).unwrap();

            render_batches.push(SkinnedRenderBatch {
                batch: batch,
                skinning_transforms_buffer: skinning_transforms_buffer,
            });
        }

        Ok(SkinnedRenderer {
            render_batches: render_batches,
            skeleton: skeleton.clone(),
        })
    }

    pub fn render<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        D: Device<Resources = R, CommandBuffer = C>,
        O: gfx::render::target::Output<R>,
    >(
        &mut self,
        graphics: &mut gfx::Graphics<D, F>,
        output: &O,
        view: [[f32; 4]; 4],
        projection: [[f32; 4]; 4],
        joint_poses: &[Matrix4<f32>]
    ) {

        let skinning_transforms = self.calculate_skinning_transforms(&joint_poses);

        for material in self.render_batches.iter_mut() {
            material.batch.params.u_model_view = view;
            material.batch.params.u_model_view_proj = projection;

            // FIXME -- should all be able to share the same buffer
            graphics.factory.update_buffer(&material.skinning_transforms_buffer, &skinning_transforms[..], 0);

            graphics.draw(&material.batch, output).unwrap();
        }
    }

    ///
    /// TODO - don't allocate a new vector
    ///
    pub fn calculate_skinning_transforms(&self, global_poses: &[Matrix4<f32>]) -> Vec<Matrix4<f32>> {

        use std::f32::consts::PI;
        use std::num::{Float};

        self.skeleton.joints.iter().enumerate().map(|(i, joint)| {
            row_mat4_mul(global_poses[i], joint.inverse_bind_pose)
        }).collect()
    }
}

#[shader_param]
struct SkinnedShaderParams<R: gfx::Resources> {
    u_model_view_proj: [[f32; 4]; 4],
    u_model_view: [[f32; 4]; 4],
    u_skinning_transforms: gfx::RawBufferHandle<R>,
    u_texture: gfx::shade::TextureParam<R>,
}

#[vertex_format]
#[derive(Copy)]
#[derive(Clone)]
#[derive(Debug)]
struct SkinnedVertex {
    pos: [f32; 3],
    normal: [f32; 3],
    uv: [f32; 2],
    joint_indices: [i32; 4],
    joint_weights: [f32; 4], // TODO last weight is redundant
}

impl Default for SkinnedVertex {
    fn default() -> SkinnedVertex {
        SkinnedVertex {
            pos: [0.0; 3],
            normal: [0.0; 3],
            uv: [0.0; 2],
            joint_indices: [0; 4],
            joint_weights: [0.0; 4],
        }
    }
}

static SKINNED_VERTEX_SHADER: &'static [u8] = b"
    #version 150 core

    uniform mat4 u_model_view_proj;
    uniform mat4 u_model_view;

    const int MAX_JOINTS = 64;

    uniform u_skinning_transforms {
        mat4 skinning_transforms[MAX_JOINTS];
    };

    in vec3 pos, normal;
    in vec2 uv;

    in ivec4 joint_indices;
    in vec4 joint_weights;

    out vec3 v_normal;
    out vec2 v_TexCoord;

    void main() {
        v_TexCoord = vec2(uv.x, 1 - uv.y); // this feels like a bug with gfx?

        vec4 adjustedVertex;
        vec4 adjustedNormal;

        vec4 bindPoseVertex = vec4(pos, 1.0);
        vec4 bindPoseNormal = vec4(normal, 0.0);

        adjustedVertex = bindPoseVertex * skinning_transforms[joint_indices.x] * joint_weights.x;
        adjustedNormal = bindPoseNormal * skinning_transforms[joint_indices.x] * joint_weights.x;

        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.y] * joint_weights.y;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.y] * joint_weights.y;

        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.z] * joint_weights.z;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.z] * joint_weights.z;

        // TODO just use remainder for this weight?
        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.a] * joint_weights.a;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.a] * joint_weights.a;

        gl_Position = u_model_view_proj * adjustedVertex;
        v_normal = normalize(u_model_view * adjustedNormal).xyz;
    }
";

static SKINNED_FRAGMENT_SHADER: &'static [u8] = b"
    #version 150

    uniform sampler2D u_texture;

    in vec3 v_normal;
    out vec4 out_color;

    in vec2 v_TexCoord;

    void main() {
        vec4 texColor = texture(u_texture, v_TexCoord);

        // unidirectional light in direction as camera
        vec3 light = vec3(0.0, 0.0, 1.0);
        light = normalize(light);
        float intensity = max(dot(v_normal, light), 0.0);

        out_color = vec4(intensity, intensity, intensity, 1.0) * texColor;
    }
";

fn vtn_to_vertex(a: collada::VTNIndex, obj: &collada::Object) -> SkinnedVertex
{
    let mut vertex: SkinnedVertex = Default::default();
    let position = obj.vertices[a.0];

    vertex.pos = [position.x as f32, position.y as f32, position.z as f32];

    if obj.joint_weights.len() == obj.vertices.len() {
        let weights = obj.joint_weights[a.0];
        vertex.joint_weights = weights.weights;
        vertex.joint_indices = [
            weights.joints[0] as i32,
            weights.joints[1] as i32,
            weights.joints[2] as i32,
            weights.joints[3] as i32,
        ];
    }

    if let Some(uv) = a.1 {
        let uv = obj.tex_vertices[uv];
        vertex.uv = [uv.x as f32, uv.y as f32];
    }

    if let Some(normal) = a.2 {
        let normal = obj.normals[normal];
        vertex.normal = [normal.x as f32, normal.y as f32, normal.z as f32];
    }

    vertex
}

fn get_vertex_index_data(obj: &collada::Object, vertex_data: &mut Vec<SkinnedVertex>, index_data: &mut Vec<u32>) {
    for geom in obj.geometry.iter() {
        let start = index_data.len();
        let mut i = vertex_data.len() as u32;
        let mut uvs: u32 = 0;
        let mut normals: u32 = 0;
        {
            let mut add = |a: collada::VTNIndex| {
                if let Some(_) = a.1 { uvs += 1; }
                if let Some(_) = a.2 { normals += 1; }
                vertex_data.push(vtn_to_vertex(a, obj));
                index_data.push(i);
                i += 1;
            };
            for shape in geom.shapes.iter() {
                match shape {
                    &collada::Shape::Triangle(a, b, c) => {
                        add(a);
                        add(b);
                        add(c);
                    }
                    _ => {}
                }
            }
        }
    }
}
<commit_msg>No longer using gfx::Graphics in SkinnedRenderer<commit_after>use std::default::Default;
use std::path::Path;

use collada;
use gfx;
use gfx::traits::*;
use gfx_texture;

use math::*;
use skeleton::Skeleton;

const MAX_JOINTS: usize = 64;

pub struct SkinnedRenderBatch<R: gfx::Resources> {
    skinning_transforms_buffer: gfx::BufferHandle<R, [[f32; 4]; 4]>,
    batch: gfx::batch::RefBatch<SkinnedShaderParams<R>>,
}

pub struct SkinnedRenderer<R: gfx::Resources> {
    skeleton: Skeleton, // TODO Should this be a ref? Should this just be the joints?
    render_batches: Vec<SkinnedRenderBatch<R>>,
    context: gfx::render::batch::Context<R>,
}

impl<R: gfx::Resources> SkinnedRenderer<R> {

    pub fn from_collada<
        F: gfx::Factory<R>,
    > (
        factory: &mut F,
        collada_document: collada::document::ColladaDocument,
        texture_paths: Vec<&str>, // TODO - read from the COLLADA document (if available)
    ) -> Result<SkinnedRenderer<R>, gfx::ProgramError> {

        let program = match factory.link_program(SKINNED_VERTEX_SHADER.clone(), SKINNED_FRAGMENT_SHADER.clone()) {
            Ok(program_handle) => program_handle,
            Err(e) => return Err(e),
        };

        let obj_set = collada_document.get_obj_set().unwrap();

        let mut skeleton_set = collada_document.get_skeletons().unwrap();
        let mut animations = collada_document.get_animations();
        let skeleton = Skeleton::from_collada(&skeleton_set[0]);

        let mut render_batches = Vec::new();

        let mut context = gfx::render::batch::Context::new();

        for (i, object) in obj_set.objects.iter().enumerate().take(6) {

            let mut vertex_data: Vec<SkinnedVertex> = Vec::new();
            let mut index_data: Vec<u32> = Vec::new();

            get_vertex_index_data(&object, &mut vertex_data, &mut index_data);

            let mesh = factory.create_mesh(vertex_data.as_slice());

            let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

            let slice = factory
                .create_buffer_index::<u32>(index_data.as_slice())
                .to_slice(gfx::PrimitiveType::TriangleList);

            let skinning_transforms_buffer = factory.create_buffer::<[[f32; 4]; 4]>(MAX_JOINTS, gfx::BufferUsage::Dynamic);

            let texture = gfx_texture::Texture::from_path(
                factory,
                &Path::new(&texture_paths[i]),
                &gfx_texture::Settings::new()
            ).unwrap();

            let sampler = factory.create_sampler(
                gfx::tex::SamplerInfo::new(
                    gfx::tex::FilterMethod::Trilinear,
                    gfx::tex::WrapMode::Clamp
                )
            );

            let shader_params = SkinnedShaderParams {
                u_model_view_proj: mat4_id(),
                u_model_view: mat4_id(),
                u_skinning_transforms: skinning_transforms_buffer.raw().clone(),
                u_texture: (texture.handle, Some(sampler)),
            };

            let batch: gfx::batch::RefBatch<SkinnedShaderParams<R>> = context.make_batch(&program, shader_params, &mesh, slice, &state).unwrap();

            render_batches.push(SkinnedRenderBatch {
                batch: batch,
                skinning_transforms_buffer: skinning_transforms_buffer,
            });
        }

        Ok(SkinnedRenderer {
            render_batches: render_batches,
            skeleton: skeleton.clone(),
            context: context,
        })
    }

    pub fn render<
        C: gfx::CommandBuffer<R>,
        F: gfx::Factory<R>,
        O: gfx::render::target::Output<R>,
    >(
        &mut self,
        renderer: &mut gfx::Renderer<R, C>,
        factory: &mut F,
        output: &O,
        view: [[f32; 4]; 4],
        projection: [[f32; 4]; 4],
        joint_poses: &[Matrix4<f32>]
    ) {

        let skinning_transforms = self.calculate_skinning_transforms(&joint_poses);

        for material in self.render_batches.iter_mut() {
            material.batch.params.u_model_view = view;
            material.batch.params.u_model_view_proj = projection;

            // FIXME -- should all be able to share the same buffer
            factory.update_buffer(&material.skinning_transforms_buffer, &skinning_transforms[..], 0);

            renderer.draw(&(&material.batch, &self.context), output).unwrap();
        }
    }

    ///
    /// TODO - don't allocate a new vector
    ///
    pub fn calculate_skinning_transforms(&self, global_poses: &[Matrix4<f32>]) -> Vec<Matrix4<f32>> {

        use std::f32::consts::PI;
        use std::num::{Float};

        self.skeleton.joints.iter().enumerate().map(|(i, joint)| {
            row_mat4_mul(global_poses[i], joint.inverse_bind_pose)
        }).collect()
    }
}

#[shader_param]
struct SkinnedShaderParams<R: gfx::Resources> {
    u_model_view_proj: [[f32; 4]; 4],
    u_model_view: [[f32; 4]; 4],
    u_skinning_transforms: gfx::RawBufferHandle<R>,
    u_texture: gfx::shade::TextureParam<R>,
}

#[vertex_format]
#[derive(Copy)]
#[derive(Clone)]
#[derive(Debug)]
struct SkinnedVertex {
    pos: [f32; 3],
    normal: [f32; 3],
    uv: [f32; 2],
    joint_indices: [i32; 4],
    joint_weights: [f32; 4], // TODO last weight is redundant
}

impl Default for SkinnedVertex {
    fn default() -> SkinnedVertex {
        SkinnedVertex {
            pos: [0.0; 3],
            normal: [0.0; 3],
            uv: [0.0; 2],
            joint_indices: [0; 4],
            joint_weights: [0.0; 4],
        }
    }
}

static SKINNED_VERTEX_SHADER: &'static [u8] = b"
    #version 150 core

    uniform mat4 u_model_view_proj;
    uniform mat4 u_model_view;

    const int MAX_JOINTS = 64;

    uniform u_skinning_transforms {
        mat4 skinning_transforms[MAX_JOINTS];
    };

    in vec3 pos, normal;
    in vec2 uv;

    in ivec4 joint_indices;
    in vec4 joint_weights;

    out vec3 v_normal;
    out vec2 v_TexCoord;

    void main() {
        v_TexCoord = vec2(uv.x, 1 - uv.y); // this feels like a bug with gfx?

        vec4 adjustedVertex;
        vec4 adjustedNormal;

        vec4 bindPoseVertex = vec4(pos, 1.0);
        vec4 bindPoseNormal = vec4(normal, 0.0);

        adjustedVertex = bindPoseVertex * skinning_transforms[joint_indices.x] * joint_weights.x;
        adjustedNormal = bindPoseNormal * skinning_transforms[joint_indices.x] * joint_weights.x;

        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.y] * joint_weights.y;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.y] * joint_weights.y;

        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.z] * joint_weights.z;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.z] * joint_weights.z;

        // TODO just use remainder for this weight?
        adjustedVertex = adjustedVertex + bindPoseVertex * skinning_transforms[joint_indices.a] * joint_weights.a;
        adjustedNormal = adjustedNormal + bindPoseNormal * skinning_transforms[joint_indices.a] * joint_weights.a;

        gl_Position = u_model_view_proj * adjustedVertex;
        v_normal = normalize(u_model_view * adjustedNormal).xyz;
    }
";

static SKINNED_FRAGMENT_SHADER: &'static [u8] = b"
    #version 150

    uniform sampler2D u_texture;

    in vec3 v_normal;
    out vec4 out_color;

    in vec2 v_TexCoord;

    void main() {
        vec4 texColor = texture(u_texture, v_TexCoord);

        // unidirectional light in direction as camera
        vec3 light = vec3(0.0, 0.0, 1.0);
        light = normalize(light);
        float intensity = max(dot(v_normal, light), 0.0);

        out_color = vec4(intensity, intensity, intensity, 1.0) * texColor;
    }
";

fn vtn_to_vertex(a: collada::VTNIndex, obj: &collada::Object) -> SkinnedVertex
{
    let mut vertex: SkinnedVertex = Default::default();
    let position = obj.vertices[a.0];

    vertex.pos = [position.x as f32, position.y as f32, position.z as f32];

    if obj.joint_weights.len() == obj.vertices.len() {
        let weights = obj.joint_weights[a.0];
        vertex.joint_weights = weights.weights;
        vertex.joint_indices = [
            weights.joints[0] as i32,
            weights.joints[1] as i32,
            weights.joints[2] as i32,
            weights.joints[3] as i32,
        ];
    }

    if let Some(uv) = a.1 {
        let uv = obj.tex_vertices[uv];
        vertex.uv = [uv.x as f32, uv.y as f32];
    }

    if let Some(normal) = a.2 {
        let normal = obj.normals[normal];
        vertex.normal = [normal.x as f32, normal.y as f32, normal.z as f32];
    }

    vertex
}

fn get_vertex_index_data(obj: &collada::Object, vertex_data: &mut Vec<SkinnedVertex>, index_data: &mut Vec<u32>) {
    for geom in obj.geometry.iter() {
        let start = index_data.len();
        let mut i = vertex_data.len() as u32;
        let mut uvs: u32 = 0;
        let mut normals: u32 = 0;
        {
            let mut add = |a: collada::VTNIndex| {
                if let Some(_) = a.1 { uvs += 1; }
                if let Some(_) = a.2 { normals += 1; }
                vertex_data.push(vtn_to_vertex(a, obj));
                index_data.push(i);
                i += 1;
            };
            for shape in geom.shapes.iter() {
                match shape {
                    &collada::Shape::Triangle(a, b, c) => {
                        add(a);
                        add(b);
                        add(c);
                    }
                    _ => {}
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use syntax::ast::expr::*;
use syntax::ast::constant::*;
use syntax::ast::op::*;
use syntax::ast::types::*;
use JSType = syntax::ast::types::Type;
use stdlib::value::{Value, VNull, ResultValue, to_value};
use stdlib::*;
use run::exec::Executor;
use std::gc::Gc;
use std::c_str::CString;
use jit::{get_type, Context, Function, Type, Compilable};
use jit::{UByte, SysChar, SysBool, Int, UInt, Pointer, Float64};
use jit::{init, supports_threads, supports_virtual_memory, uses_interpreter};
use JitValue = jit::Value;

fn compile_type(js_type:&JSType) -> Type {
	match *js_type {
		UndefinedType | NullType | NativeObjectType | ObjectType | AnyType => get_type::<*int>(),
		FunctionType => get_type::<fn(*int) -> *int>(),
		StringType => get_type::<String>(),
		BooleanType => get_type::<bool>(),
		NumberType => get_type::<f64>(),
		IntegerType => get_type::<i32>(),
		AnyOfType(ref types) => {
			fail!("Unknown types: {}", types)
		}
	}
}
/// A Javascript JIT compiler
pub struct JITCompiler {
	/// The JIT Context
	context: Context,
	/// An object representing the global object
	pub global: Value
}
impl Executor<Function> for JITCompiler {
	fn new() -> JITCompiler {
		debug!("Initialising LibJIT...");
		init();
		debug!("JIT supports threads? {}", supports_threads());
		debug!("JIT supports virtual memory? {}", supports_virtual_memory());
		debug!("JIT using interpreter? {}", uses_interpreter());
		debug!("Initialising global object...");
		let global = Value::new_obj(None);
		object::init(global);
		console::init(global);
		math::init(global);
		array::init(global);
		function::init(global);
		json::init(global);
		number::init(global);
		error::init(global);
		string::init(global);
		uri::init(global);
		JITCompiler {
			context: Context::new(),
			global: global
		}
	}
	#[inline(always)]
	fn set_global(&mut self, name:String, val:Value) -> Value {
		self.global.set_field(name, val)
	}
	#[inline(always)]
	fn get_global(&self, name:String) -> Value {
		self.global.get_field(name)
	}
	fn compile(&self, expr: &Expr) -> Function {
		debug!("Compiling {} in builder", expr);
		self.context.build(|| {
			let default_sig_t = get_type::<fn(*int, *int, *int) -> *int>();
			let func = Function::new(&self.context, &default_sig_t);
			let value = compile_value(&func, expr);
			func.insn_return(&convert_to_value(&func, &value));
			func.set_optimization_level(5);
			func.set_recompilable();
			func.compile();
			func
		})
	}
	fn run(&mut self, comp:&Function) -> ResultValue {
		debug!("Running function");
		debug!("There are {} functions in context", self.context.iter_funcs().size_hint());
		let func: fn(Value, Value, Value) -> Value = unsafe { comp.closure3() };
		return Ok(func(self.global, self.global, self.global));
	}
}

fn convert_to_value(func:&Function, val:&JitValue) -> JitValue {
	let value_t = get_type::<*int>();
	let undef_value = Value::undefined;
	let val_type = val.get_type();
	let val_kind = val_type.get_kind();
	debug!("Converting JIT value of kind {} to Javascript value", val_kind.bits());
	if val_kind.contains(SysBool) || val_kind.contains(UByte) {
		let bool_value = to_value::<bool>;
		let sig = get_type::<fn(bool) -> *int>();
		func.insn_call_native1("bool_value", bool_value, &sig, &mut [val])
	} else if val_kind.contains(Pointer) {
		let ref_t = val_type.get_ref();
		if ref_t.get_kind().contains(SysChar) {
			fn string_value(val: *i8) -> Value {
				unsafe {
					let text = CString::new(val, false);
					to_value(text.as_str().unwrap().into_string())
				}
			}
			let sig = get_type::<fn(String) -> *int>();
			func.insn_call_native1("string_value", string_value, &sig, &mut [val])
		} else {
			fn ptr_value(ptr: *i8) -> Value {
				match ptr.to_uint() {
					0u => Value::undefined(),
					1u => Value {
						ptr: Gc::new(VNull)
					},
					ptr => fail!("Invalid pointer: {}", ptr)
				}
			}
			let sig = get_type::<fn(*i8) -> *int>();
			func.insn_call_native1("ptr_value", ptr_value, &sig, &mut [val])
		}
	} else if val_kind.contains(Int) || val_kind.contains(UInt) {
		let int_value = to_value::<i32>;
		let sig = get_type::<fn(i32) -> *int>();
		func.insn_call_native1("int_value", int_value, &sig, &mut [val])
	} else if val_kind.contains(Float64) {
		let float_value = to_value::<f64>;
		let sig = get_type::<fn(f64) -> *int>();
		func.insn_call_native1("float_value", float_value, &sig, &mut [val])
	} else {
		fail!("Invalid kind {}", val_kind.bits())
	}
}

fn compile_value(func:&Function, expr: &Expr) -> JitValue {
	let value_t = get_type::<*int>();
	let cstring_t = get_type::<*char>();
	let create_value_sig = get_type::<fn() -> *int>();
	let undefined = || {
		let ptr = JitValue::new(func, &get_type::<*int>());
		let val = 0u8.compile(func);
		func.insn_store(&ptr, &val);
		ptr
	};
	let global = func.get_param(0);
	let scope = func.get_param(1);
	let this = func.get_param(2);
	debug!("Compiling {} into a LibJIT value", expr);
	match expr.def {
		ConstExpr(CNull) => {
			let ptr = JitValue::new(func, &get_type::<*int>());
			let val = 1u8.compile(func);
			func.insn_store(&ptr, &val);
			ptr
		},
		ConstExpr(CUndefined) => {
			undefined()
		},
		ConstExpr(CBool(v)) => {
			v.compile(func)
		},
		ConstExpr(CNum(n)) => {
			n.compile(func)
		},
		ConstExpr(CString(ref s)) => {
			s.compile(func)
		},
		BinOpExpr(BinNum(OpAdd), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_add(&i_a, &i_b)
		},
		BinOpExpr(BinNum(OpSub), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_sub(&i_a, &i_b)
		},
		BinOpExpr(BinNum(OpMul), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_mul(&i_a, &i_b)
		},
		BinOpExpr(BinNum(OpDiv), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_div(&i_a, &i_b)
		},
		BinOpExpr(BinNum(OpMod), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_rem(&i_a, &i_b)
		},
		BinOpExpr(BinBit(BitAnd), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_and(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinBit(BitOr), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_or(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinBit(BitXor), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_xor(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinBit(BitShl), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_shl(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinBit(BitShr), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_shr(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinComp(CompEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_eq(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompNotEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictNotEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_neq(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompLessThan), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_lt(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompLessThanOrEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_leq(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompGreaterThan), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_gt(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompGreaterThanOrEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_geq(&i_a, &i_b), &get_type::<bool>(), false)
		},
		UnaryOpExpr(UnaryMinus, ref a) => {
			func.insn_neg(&compile_value(func, *a))
		},
		UnaryOpExpr(UnaryNot, ref a) => {
			let mut val = compile_value(func, *a);
			val = func.insn_convert(&val, &get_type::<bool>(), false);
			val = func.insn_neg(&val);
			func.insn_convert(&val, &get_type::<bool>(), false)
		},
		UnaryOpExpr(UnaryPlus, ref a) => {
			compile_value(func, *a)
		},
		BlockExpr(ref exprs) => {
			let mut result = undefined();
			let last = exprs.last();
			for expr in exprs.iter() {
				let res = compile_value(func, expr);
				if expr == last.unwrap() {
					result = res;
				}
			}
			result
		},
		ReturnExpr(Some(ref ex)) => {
			let ret = compile_value(func, *ex);
			func.insn_return(&convert_to_value(func, &ret));
			ret
		}
		_ => fail!("Unimplemented {}", expr)
	}
}<commit_msg>Remove unused variables<commit_after>use syntax::ast::expr::*;
use syntax::ast::constant::*;
use syntax::ast::op::*;
use syntax::ast::types::*;
use JSType = syntax::ast::types::Type;
use stdlib::value::{Value, VNull, ResultValue, to_value};
use stdlib::*;
use run::exec::Executor;
use std::gc::Gc;
use std::c_str::CString;
use jit::{get_type, Context, Function, Type, Compilable};
use jit::{UByte, SysChar, SysBool, Int, UInt, Pointer, Float64};
use jit::{init, supports_threads, supports_virtual_memory, uses_interpreter};
use JitValue = jit::Value;

fn compile_type(js_type:&JSType) -> Type {
	match *js_type {
		UndefinedType | NullType | NativeObjectType | ObjectType | AnyType => get_type::<*int>(),
		FunctionType => get_type::<fn(*int) -> *int>(),
		StringType => get_type::<String>(),
		BooleanType => get_type::<bool>(),
		NumberType => get_type::<f64>(),
		IntegerType => get_type::<i32>(),
		AnyOfType(ref types) => {
			fail!("Unknown types: {}", types)
		}
	}
}
/// A Javascript JIT compiler
pub struct JITCompiler {
	/// The JIT Context
	context: Context,
	/// An object representing the global object
	pub global: Value
}
impl Executor<Function> for JITCompiler {
	fn new() -> JITCompiler {
		debug!("Initialising LibJIT...");
		init();
		debug!("JIT supports threads? {}", supports_threads());
		debug!("JIT supports virtual memory? {}", supports_virtual_memory());
		debug!("JIT using interpreter? {}", uses_interpreter());
		debug!("Initialising global object...");
		let global = Value::new_obj(None);
		object::init(global);
		console::init(global);
		math::init(global);
		array::init(global);
		function::init(global);
		json::init(global);
		number::init(global);
		error::init(global);
		string::init(global);
		uri::init(global);
		JITCompiler {
			context: Context::new(),
			global: global
		}
	}
	#[inline(always)]
	fn set_global(&mut self, name:String, val:Value) -> Value {
		self.global.set_field(name, val)
	}
	#[inline(always)]
	fn get_global(&self, name:String) -> Value {
		self.global.get_field(name)
	}
	fn compile(&self, expr: &Expr) -> Function {
		debug!("Compiling {} in builder", expr);
		self.context.build(|| {
			let default_sig_t = get_type::<fn(*int, *int, *int) -> *int>();
			let func = Function::new(&self.context, &default_sig_t);
			let value = compile_value(&func, expr);
			func.insn_return(&convert_to_value(&func, &value));
			func.set_optimization_level(5);
			func.set_recompilable();
			func.compile();
			func
		})
	}
	fn run(&mut self, comp:&Function) -> ResultValue {
		debug!("Running function");
		debug!("There are {} functions in context", self.context.iter_funcs().size_hint());
		let func: fn(Value, Value, Value) -> Value = unsafe { comp.closure3() };
		return Ok(func(self.global, self.global, self.global));
	}
}

fn convert_to_value(func:&Function, val:&JitValue) -> JitValue {
	let val_type = val.get_type();
	let val_kind = val_type.get_kind();
	debug!("Converting JIT value of kind {} to Javascript value", val_kind.bits());
	if val_kind.contains(SysBool) || val_kind.contains(UByte) {
		let bool_value = to_value::<bool>;
		let sig = get_type::<fn(bool) -> *int>();
		func.insn_call_native1("bool_value", bool_value, &sig, &mut [val])
	} else if val_kind.contains(Pointer) {
		let ref_t = val_type.get_ref();
		if ref_t.get_kind().contains(SysChar) {
			fn string_value(val: *i8) -> Value {
				unsafe {
					let text = CString::new(val, false);
					to_value(text.as_str().unwrap().into_string())
				}
			}
			let sig = get_type::<fn(String) -> *int>();
			func.insn_call_native1("string_value", string_value, &sig, &mut [val])
		} else {
			fn ptr_value(ptr: *i8) -> Value {
				match ptr.to_uint() {
					0u => Value::undefined(),
					1u => Value {
						ptr: Gc::new(VNull)
					},
					ptr => fail!("Invalid pointer: {}", ptr)
				}
			}
			let sig = get_type::<fn(*i8) -> *int>();
			func.insn_call_native1("ptr_value", ptr_value, &sig, &mut [val])
		}
	} else if val_kind.contains(Int) || val_kind.contains(UInt) {
		let int_value = to_value::<i32>;
		let sig = get_type::<fn(i32) -> *int>();
		func.insn_call_native1("int_value", int_value, &sig, &mut [val])
	} else if val_kind.contains(Float64) {
		let float_value = to_value::<f64>;
		let sig = get_type::<fn(f64) -> *int>();
		func.insn_call_native1("float_value", float_value, &sig, &mut [val])
	} else {
		fail!("Invalid kind {}", val_kind.bits())
	}
}

fn compile_value(func:&Function, expr: &Expr) -> JitValue {
	let undefined = || {
		let ptr = JitValue::new(func, &get_type::<*int>());
		let val = 0u8.compile(func);
		func.insn_store(&ptr, &val);
		ptr
	};
	let global = func.get_param(0);
	let scope = func.get_param(1);
	let this = func.get_param(2);
	debug!("Compiling {} into a LibJIT value", expr);
	match expr.def {
		ConstExpr(CNull) => {
			let ptr = JitValue::new(func, &get_type::<*int>());
			let val = 1u8.compile(func);
			func.insn_store(&ptr, &val);
			ptr
		},
		ConstExpr(CUndefined) => {
			undefined()
		},
		ConstExpr(CBool(v)) => {
			v.compile(func)
		},
		ConstExpr(CNum(n)) => {
			n.compile(func)
		},
		ConstExpr(CString(ref s)) => {
			s.compile(func)
		},
		BinOpExpr(BinNum(OpAdd), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_add(&i_a, &i_b)
		},
		BinOpExpr(BinNum(OpSub), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_sub(&i_a, &i_b)
		},
		BinOpExpr(BinNum(OpMul), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_mul(&i_a, &i_b)
		},
		BinOpExpr(BinNum(OpDiv), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_div(&i_a, &i_b)
		},
		BinOpExpr(BinNum(OpMod), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_rem(&i_a, &i_b)
		},
		BinOpExpr(BinBit(BitAnd), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_and(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinBit(BitOr), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_or(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinBit(BitXor), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_xor(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinBit(BitShl), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_shl(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinBit(BitShr), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_shr(&i_a, &i_b), &get_type::<i32>(), false)
		},
		BinOpExpr(BinComp(CompEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_eq(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompNotEqual), ref a, ref b) | BinOpExpr(BinComp(CompStrictNotEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_neq(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompLessThan), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_lt(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompLessThanOrEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_leq(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompGreaterThan), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_gt(&i_a, &i_b), &get_type::<bool>(), false)
		},
		BinOpExpr(BinComp(CompGreaterThanOrEqual), ref a, ref b) => {
			let i_a = compile_value(func, *a);
			let i_b = compile_value(func, *b);
			func.insn_convert(&func.insn_geq(&i_a, &i_b), &get_type::<bool>(), false)
		},
		UnaryOpExpr(UnaryMinus, ref a) => {
			func.insn_neg(&compile_value(func, *a))
		},
		UnaryOpExpr(UnaryNot, ref a) => {
			let mut val = compile_value(func, *a);
			val = func.insn_convert(&val, &get_type::<bool>(), false);
			val = func.insn_neg(&val);
			func.insn_convert(&val, &get_type::<bool>(), false)
		},
		UnaryOpExpr(UnaryPlus, ref a) => {
			compile_value(func, *a)
		},
		BlockExpr(ref exprs) => {
			let mut result = undefined();
			let last = exprs.last();
			for expr in exprs.iter() {
				let res = compile_value(func, expr);
				if expr == last.unwrap() {
					result = res;
				}
			}
			result
		},
		ReturnExpr(Some(ref ex)) => {
			let ret = compile_value(func, *ex);
			func.insn_return(&convert_to_value(func, &ret));
			ret
		}
		_ => fail!("Unimplemented {}", expr)
	}
}<|endoftext|>


<commit_before>// Copyright 2017, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
use std::fmt;
use std::mem;
use super::{Encoder, EncoderError, EncodeResult, ENCODER_SAM};
use super::EncoderState::*;
// use std::convert::Into;
use serde::ser::*;

// pub struct RegSerializer {
//     key: RegKey,
// }

// impl RegSerializer {
//     pub fn new(key: &RegKey) -> Self {
//         RegSerializer { key: key.open_subkey("").unwrap() }
//     }
// }

impl Error for EncoderError {
    fn custom<T: fmt::Display>(msg: T) -> Self {
        EncoderError::SerializerError(format!("{}", msg))
    }
}

impl<'a> Serializer for &'a mut Encoder {
    type Ok = ();
    type Error = EncoderError;

    type SerializeSeq = RegSerializeSeqStub;
    type SerializeTuple = RegSerializeTupleStub;
    type SerializeTupleStruct = RegSerializeTupleStructStub;
    type SerializeTupleVariant = RegSerializeTupleVariantStub;
    type SerializeMap = RegCompound<'a>;
    type SerializeStruct = RegSerializeStructStub<'a>;
    type SerializeStructVariant = RegSerializeStructVariantStub;

    fn serialize_bool(self, value: bool) -> EncodeResult<Self::Ok> {
        self.serialize_u32(value as u32)
    }

    fn serialize_i8(self, value: i8) -> EncodeResult<Self::Ok> {
        self.serialize_i64(value as i64)
    }

    fn serialize_i16(self, value: i16) -> EncodeResult<Self::Ok> {
        self.serialize_i64(value as i64)
    }

    fn serialize_i32(self, value: i32) -> EncodeResult<Self::Ok> {
        self.serialize_i64(value as i64)
    }

    fn serialize_i64(self, value: i64) -> EncodeResult<Self::Ok> {
        let s = value.to_string();
        emit_value!(self, s)
    }

    fn serialize_u8(self, value: u8) -> EncodeResult<Self::Ok> {
        self.serialize_u32(value as u32)
    }

    fn serialize_u16(self, value: u16) -> EncodeResult<Self::Ok> {
        self.serialize_u32(value as u32)
    }

    fn serialize_u32(self, value: u32) -> EncodeResult<Self::Ok> {
        emit_value!(self, value)
    }

    fn serialize_u64(self, value: u64) -> EncodeResult<Self::Ok> {
        emit_value!(self, value)
    }

    fn serialize_f32(self, value: f32) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_f32")
    }

    fn serialize_f64(self, value: f64) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_f64")
    }

    fn serialize_char(self, value: char) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_char")
    }

    fn serialize_str(self, value: &str) -> EncodeResult<Self::Ok> {
        emit_value!(self, value)
    }

    fn serialize_bytes(self, value: &[u8]) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_bytes")
    }

    fn serialize_none(self) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_none")
    }

    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_some")
    }

    fn serialize_unit(self) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_unit")
    }

    fn serialize_unit_struct(self, name: &'static str) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_unit_struct")
    }

    fn serialize_unit_variant(self,
                              name: &'static str,
                              variant_index: u32,
                              variant: &'static str)
                              -> EncodeResult<Self::Ok> {
        no_impl!("serialize_unit_variant")
    }

    fn serialize_newtype_struct<T: ?Sized + Serialize>(self,
                                                       name: &'static str,
                                                       value: &T)
                                                       -> EncodeResult<Self::Ok> {
        no_impl!("serialize_newtype_struct")
    }

    fn serialize_newtype_variant<T: ?Sized + Serialize>(self,
                                                        name: &'static str,
                                                        variant_index: u32,
                                                        variant: &'static str,
                                                        value: &T)
                                                        -> EncodeResult<Self::Ok> {
        no_impl!("serialize_newtype_variant")
    }

    fn serialize_seq(self, len: Option<usize>) -> EncodeResult<Self::SerializeSeq> {
        no_impl!("serialize_seq")
    }

    fn serialize_tuple(self, len: usize) -> EncodeResult<Self::SerializeTuple> {
        no_impl!("serialize_tuple")
    }

    fn serialize_tuple_struct(self,
                              name: &'static str,
                              len: usize)
                              -> EncodeResult<Self::SerializeTupleStruct> {
        no_impl!("serialize_tuple_struct")
    }

    fn serialize_tuple_variant(self,
                               name: &'static str,
                               variant_index: u32,
                               variant: &'static str,
                               len: usize)
                               -> EncodeResult<Self::SerializeTupleVariant> {
        no_impl!("serialize_tuple_variant")
    }

    fn serialize_map(self, len: Option<usize>) -> EncodeResult<Self::SerializeMap> {
        Ok(RegCompound { enc: self })
    }

    fn serialize_struct(self,
                        name: &'static str,
                        len: usize)
                        -> EncodeResult<Self::SerializeStruct> {
        // )
        match mem::replace(&mut self.state, Start) {
            Start => {
                // root structure
                Ok(RegSerializeStructStub { enc: self, is_root: true })
            }
            NextKey(ref s) => {
                // nested structure
                match self.keys[self.keys.len() - 1]
                    .create_subkey_transacted_with_flags(&s, &self.tr, ENCODER_SAM) {
                    Ok(subkey) => {
                        self.keys.push(subkey);
                        Ok(RegSerializeStructStub { enc: self, is_root: true })
                    }
                    Err(err) => Err(EncoderError::IoError(err)),
                }
            }
        }
    }

    fn serialize_struct_variant(self,
                                name: &'static str,
                                variant_index: u32,
                                variant: &'static str,
                                len: usize)
                                -> EncodeResult<Self::SerializeStructVariant> {
        no_impl!("serialize_struct_variant")
    }
}

pub struct RegSerializeSeqStub {}

impl SerializeSeq for RegSerializeSeqStub {
    type Ok = ();
    type Error = EncoderError;
    fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeSeq::serialize_element")
    }
    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeSeq::end")
    }
}

pub struct RegSerializeTupleStub {}

impl SerializeTuple for RegSerializeTupleStub {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTuple::serialize_element")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTuple::end")
    }
}

pub struct RegSerializeTupleStructStub {}

impl SerializeTupleStruct for RegSerializeTupleStructStub {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTupleStruct::serialize_field")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTupleStruct::end")
    }
}

pub struct RegSerializeTupleVariantStub {}

impl SerializeTupleVariant for RegSerializeTupleVariantStub {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTupleVariant::serialize_field")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTupleVariant::end")
    }
}

pub struct RegCompound<'a> {
    enc: &'a mut Encoder,
}

impl<'a> SerializeMap for RegCompound<'a> {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeMap::serialize_key")
    }

    fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeMap::serialize_value")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeMap::end")
    }
}

pub struct RegSerializeStructStub<'a> {
    enc: &'a mut Encoder,
    is_root: bool
}

impl<'a> SerializeStruct for RegSerializeStructStub<'a> {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_field<T: ?Sized + Serialize>(&mut self,
                                              key: &'static str,
                                              value: &T)
                                              -> EncodeResult<Self::Ok> {
        self.enc.state = NextKey(String::from(key));
        value.serialize(&mut *self.enc)
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        if self.is_root {
            self.enc.keys.pop();
        }
        Ok(())
    }
}

pub struct RegSerializeStructVariantStub {}

impl SerializeStructVariant for RegSerializeStructVariantStub {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_field<T: ?Sized + Serialize>(&mut self,
                                              key: &'static str,
                                              value: &T)
                                              -> EncodeResult<Self::Ok> {
        no_impl!("SerializeStructVariant::serialize_field")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeStructVariant::end")
    }
}

<commit_msg>Remove commented code<commit_after>// Copyright 2017, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
use std::fmt;
use std::mem;
use super::{Encoder, EncoderError, EncodeResult, ENCODER_SAM};
use super::EncoderState::*;
use serde::ser::*;

impl Error for EncoderError {
    fn custom<T: fmt::Display>(msg: T) -> Self {
        EncoderError::SerializerError(format!("{}", msg))
    }
}

impl<'a> Serializer for &'a mut Encoder {
    type Ok = ();
    type Error = EncoderError;

    type SerializeSeq = RegSerializeSeqStub;
    type SerializeTuple = RegSerializeTupleStub;
    type SerializeTupleStruct = RegSerializeTupleStructStub;
    type SerializeTupleVariant = RegSerializeTupleVariantStub;
    type SerializeMap = RegCompound<'a>;
    type SerializeStruct = RegSerializeStructStub<'a>;
    type SerializeStructVariant = RegSerializeStructVariantStub;

    fn serialize_bool(self, value: bool) -> EncodeResult<Self::Ok> {
        self.serialize_u32(value as u32)
    }

    fn serialize_i8(self, value: i8) -> EncodeResult<Self::Ok> {
        self.serialize_i64(value as i64)
    }

    fn serialize_i16(self, value: i16) -> EncodeResult<Self::Ok> {
        self.serialize_i64(value as i64)
    }

    fn serialize_i32(self, value: i32) -> EncodeResult<Self::Ok> {
        self.serialize_i64(value as i64)
    }

    fn serialize_i64(self, value: i64) -> EncodeResult<Self::Ok> {
        let s = value.to_string();
        emit_value!(self, s)
    }

    fn serialize_u8(self, value: u8) -> EncodeResult<Self::Ok> {
        self.serialize_u32(value as u32)
    }

    fn serialize_u16(self, value: u16) -> EncodeResult<Self::Ok> {
        self.serialize_u32(value as u32)
    }

    fn serialize_u32(self, value: u32) -> EncodeResult<Self::Ok> {
        emit_value!(self, value)
    }

    fn serialize_u64(self, value: u64) -> EncodeResult<Self::Ok> {
        emit_value!(self, value)
    }

    fn serialize_f32(self, value: f32) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_f32")
    }

    fn serialize_f64(self, value: f64) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_f64")
    }

    fn serialize_char(self, value: char) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_char")
    }

    fn serialize_str(self, value: &str) -> EncodeResult<Self::Ok> {
        emit_value!(self, value)
    }

    fn serialize_bytes(self, value: &[u8]) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_bytes")
    }

    fn serialize_none(self) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_none")
    }

    fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_some")
    }

    fn serialize_unit(self) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_unit")
    }

    fn serialize_unit_struct(self, name: &'static str) -> EncodeResult<Self::Ok> {
        no_impl!("serialize_unit_struct")
    }

    fn serialize_unit_variant(self,
                              name: &'static str,
                              variant_index: u32,
                              variant: &'static str)
                              -> EncodeResult<Self::Ok> {
        no_impl!("serialize_unit_variant")
    }

    fn serialize_newtype_struct<T: ?Sized + Serialize>(self,
                                                       name: &'static str,
                                                       value: &T)
                                                       -> EncodeResult<Self::Ok> {
        no_impl!("serialize_newtype_struct")
    }

    fn serialize_newtype_variant<T: ?Sized + Serialize>(self,
                                                        name: &'static str,
                                                        variant_index: u32,
                                                        variant: &'static str,
                                                        value: &T)
                                                        -> EncodeResult<Self::Ok> {
        no_impl!("serialize_newtype_variant")
    }

    fn serialize_seq(self, len: Option<usize>) -> EncodeResult<Self::SerializeSeq> {
        no_impl!("serialize_seq")
    }

    fn serialize_tuple(self, len: usize) -> EncodeResult<Self::SerializeTuple> {
        no_impl!("serialize_tuple")
    }

    fn serialize_tuple_struct(self,
                              name: &'static str,
                              len: usize)
                              -> EncodeResult<Self::SerializeTupleStruct> {
        no_impl!("serialize_tuple_struct")
    }

    fn serialize_tuple_variant(self,
                               name: &'static str,
                               variant_index: u32,
                               variant: &'static str,
                               len: usize)
                               -> EncodeResult<Self::SerializeTupleVariant> {
        no_impl!("serialize_tuple_variant")
    }

    fn serialize_map(self, len: Option<usize>) -> EncodeResult<Self::SerializeMap> {
        Ok(RegCompound { enc: self })
    }

    fn serialize_struct(self,
                        name: &'static str,
                        len: usize)
                        -> EncodeResult<Self::SerializeStruct> {
        match mem::replace(&mut self.state, Start) {
            Start => {
                // root structure
                Ok(RegSerializeStructStub { enc: self, is_root: true })
            }
            NextKey(ref s) => {
                // nested structure
                match self.keys[self.keys.len() - 1]
                    .create_subkey_transacted_with_flags(&s, &self.tr, ENCODER_SAM) {
                    Ok(subkey) => {
                        self.keys.push(subkey);
                        Ok(RegSerializeStructStub { enc: self, is_root: true })
                    }
                    Err(err) => Err(EncoderError::IoError(err)),
                }
            }
        }
    }

    fn serialize_struct_variant(self,
                                name: &'static str,
                                variant_index: u32,
                                variant: &'static str,
                                len: usize)
                                -> EncodeResult<Self::SerializeStructVariant> {
        no_impl!("serialize_struct_variant")
    }
}

pub struct RegSerializeSeqStub {}

impl SerializeSeq for RegSerializeSeqStub {
    type Ok = ();
    type Error = EncoderError;
    fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeSeq::serialize_element")
    }
    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeSeq::end")
    }
}

pub struct RegSerializeTupleStub {}

impl SerializeTuple for RegSerializeTupleStub {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTuple::serialize_element")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTuple::end")
    }
}

pub struct RegSerializeTupleStructStub {}

impl SerializeTupleStruct for RegSerializeTupleStructStub {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTupleStruct::serialize_field")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTupleStruct::end")
    }
}

pub struct RegSerializeTupleVariantStub {}

impl SerializeTupleVariant for RegSerializeTupleVariantStub {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_field<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTupleVariant::serialize_field")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeTupleVariant::end")
    }
}

pub struct RegCompound<'a> {
    enc: &'a mut Encoder,
}

impl<'a> SerializeMap for RegCompound<'a> {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeMap::serialize_key")
    }

    fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeMap::serialize_value")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeMap::end")
    }
}

pub struct RegSerializeStructStub<'a> {
    enc: &'a mut Encoder,
    is_root: bool
}

impl<'a> SerializeStruct for RegSerializeStructStub<'a> {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_field<T: ?Sized + Serialize>(&mut self,
                                              key: &'static str,
                                              value: &T)
                                              -> EncodeResult<Self::Ok> {
        self.enc.state = NextKey(String::from(key));
        value.serialize(&mut *self.enc)
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        if self.is_root {
            self.enc.keys.pop();
        }
        Ok(())
    }
}

pub struct RegSerializeStructVariantStub {}

impl SerializeStructVariant for RegSerializeStructVariantStub {
    type Ok = ();
    type Error = EncoderError;

    fn serialize_field<T: ?Sized + Serialize>(&mut self,
                                              key: &'static str,
                                              value: &T)
                                              -> EncodeResult<Self::Ok> {
        no_impl!("SerializeStructVariant::serialize_field")
    }

    fn end(self) -> EncodeResult<Self::Ok> {
        no_impl!("SerializeStructVariant::end")
    }
}

<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::sync::{Mutex, Arc};

use input::Input;
use keyboard::Key;
use view::View;
use frontends::{Frontend, EditorEvent};
use modes::{Mode, ModeType, InsertMode, NormalMode};
use overlay::{Overlay, OverlayEvent};
use buffer::Buffer;
use command::Command;
use command::{Action, BuilderEvent, Operation, Instruction};

/// The main Editor structure
///
/// This is the top-most structure in Iota.
pub struct Editor<'e, T: Frontend> {
    buffers: Vec<Arc<Mutex<Buffer>>>,
    view: View,
    running: bool,
    frontend: T,
    mode: Box<Mode + 'e>,
}

impl<'e, T: Frontend> Editor<'e, T> {
    /// Create a new Editor instance from the given source
    pub fn new(source: Input, mode: Box<Mode + 'e>, frontend: T) -> Editor<'e, T> {
        let height = frontend.get_window_height();
        let width = frontend.get_window_width();

        let mut buffers = Vec::new();
        let buffer = Buffer::from(source);

        buffers.push(Arc::new(Mutex::new(buffer)));

        let view = View::new(buffers[0].clone(), width, height);
        Editor {
            buffers: buffers,
            view: view,
            running: true,
            frontend: frontend,
            mode: mode,
        }
    }

    /// Handle key events
    ///
    /// Key events can be handled in an Overlay, OR in the current Mode.
    ///
    /// If there is an active Overlay, the key event is sent there, which gives
    /// back an OverlayEvent. We then parse this OverlayEvent and determine if
    /// the Overlay is finished and can be cleared. The response from the
    /// Overlay is then converted to a Command and sent off to be handled.
    ///
    /// If there is no active Overlay, the key event is sent to the current
    /// Mode, which returns a Command which we dispatch to handle_command.
    fn handle_key_event(&mut self, key: Option<Key>) {
        let key = match key {
            Some(k) => k,
            None => return
        };

        let mut remove_overlay = false;
        let command = match self.view.overlay {
            Overlay::None => self.mode.handle_key_event(key),
            _             => {
                let event = self.view.overlay.handle_key_event(key);
                match event {
                    OverlayEvent::Finished(response) => {
                        remove_overlay = true;
                        self.handle_overlay_response(response)
                    }

                    _ => { BuilderEvent::Incomplete }
                }
            }
        };

        if remove_overlay {
            self.view.overlay = Overlay::None;
            self.view.clear(&mut self.frontend);
        }

        if let BuilderEvent::Complete(c) = command {
            self.handle_command(c);
        }
    }

    /// Translate the response from an Overlay to a Command wrapped in a BuilderEvent
    ///
    /// In most cases, we will just want to convert the response directly to
    /// a Command, however in some cases we will want to perform other actions
    /// first, such as in the case of Overlay::SavePrompt.
    fn handle_overlay_response(&mut self, response: Option<String>) -> BuilderEvent {
        // FIXME: This entire method neext to be updated
        match response {
            Some(data) => {
                match self.view.overlay {

                    // FIXME: this is just a temporary fix
                    Overlay::Prompt { ref data, .. } => {
                        match &**data {
                            // FIXME: need to find a better system for these commands
                            //        They should be chainable
                            //          ie: wq - save & quit
                            //        They should also take arguments
                            //          ie w file.txt - write buffer to file.txt
                            "q" | "quit" => BuilderEvent::Complete(Command::exit_editor()),
                            "w" | "write" => BuilderEvent::Complete(Command::save_buffer()),

                            _ => BuilderEvent::Incomplete
                        }
                    }

                    Overlay::SavePrompt { .. } => {
                        let path = PathBuf::from(&*data);
                        self.view.buffer.lock().unwrap().file_path = Some(path);
                        BuilderEvent::Complete(Command::save_buffer())
                    }

                    Overlay::SelectFile { .. } => {
                        let path = PathBuf::from(data);
                        let buffer = Arc::new(Mutex::new(Buffer::from(path)));
                        self.buffers.push(buffer.clone());
                        self.view.set_buffer(buffer.clone());
                        self.view.clear(&mut self.frontend);
                        BuilderEvent::Complete(Command::noop())
                    }

                    _ => BuilderEvent::Incomplete,
                }
            }
            None => BuilderEvent::Incomplete
        }
    }

    /// Handle resize events
    ///
    /// width and height represent the new height of the window.
    fn handle_resize_event(&mut self, width: usize, height: usize) {
        self.view.resize(width, height);
    }

    /// Draw the current view to the frontend
    fn draw(&mut self) {
        self.view.draw(&mut self.frontend);
    }

    /// Handle the given command, performing the associated action
    fn handle_command(&mut self, command: Command) {
        let repeat = if command.number > 0 {
            command.number
        } else { 1 };
        for _ in 0..repeat {
            match command.action {
                Action::Instruction(i) => self.handle_instruction(i, command),
                Action::Operation(o) => self.handle_operation(o, command),
            }
        }
    }

    fn handle_instruction(&mut self, instruction: Instruction, command: Command) {
        match instruction {
            Instruction::SaveBuffer => { self.view.try_save_buffer() }
            Instruction::ExitEditor => { self.running = false; }
            Instruction::SetMark(mark) => {
                if let Some(object) = command.object {
                    self.view.move_mark(mark, object)
                }
            }
            Instruction::SetOverlay(overlay_type) => {
                self.view.set_overlay(overlay_type)
            }
            Instruction::SetMode(mode) => {
                match mode {
                    ModeType::Insert => { self.mode = Box::new(InsertMode::new()) }
                    ModeType::Normal => { self.mode = Box::new(NormalMode::new()) }
                }
            }
            Instruction::SwitchToLastBuffer => {
                self.view.switch_last_buffer();
                self.view.clear(&mut self.frontend);
            }

            _ => {}
        }
    }

    fn handle_operation(&mut self, operation: Operation, command: Command) {
        match operation {
            Operation::Insert(c) => {
                for _ in 0..command.number {
                    self.view.insert_char(c)
                }
            }
            Operation::DeleteObject => {
                if let Some(obj) = command.object {
                    self.view.delete_object(obj);
                }
            }
            Operation::DeleteFromMark(m) => {
                if command.object.is_some() {
                    self.view.delete_from_mark_to_object(m, command.object.unwrap())
                }
            }
            Operation::Undo => { self.view.undo() }
            Operation::Redo => { self.view.redo() }
        }
    }

    /// Start Iota!
    pub fn start(&mut self) {
        while self.running {
            self.draw();
            self.frontend.present();
            let event = self.frontend.poll_event();

            match event {
                EditorEvent::KeyEvent(key)         => self.handle_key_event(key),
                EditorEvent::Resize(width, height) => self.handle_resize_event(width, height),

                _ => {}
            }
        }
    }
}
<commit_msg>Don't try save file if no file name give<commit_after>use std::path::PathBuf;
use std::sync::{Mutex, Arc};

use input::Input;
use keyboard::Key;
use view::View;
use frontends::{Frontend, EditorEvent};
use modes::{Mode, ModeType, InsertMode, NormalMode};
use overlay::{Overlay, OverlayEvent};
use buffer::Buffer;
use command::Command;
use command::{Action, BuilderEvent, Operation, Instruction};

/// The main Editor structure
///
/// This is the top-most structure in Iota.
pub struct Editor<'e, T: Frontend> {
    buffers: Vec<Arc<Mutex<Buffer>>>,
    view: View,
    running: bool,
    frontend: T,
    mode: Box<Mode + 'e>,
}

impl<'e, T: Frontend> Editor<'e, T> {
    /// Create a new Editor instance from the given source
    pub fn new(source: Input, mode: Box<Mode + 'e>, frontend: T) -> Editor<'e, T> {
        let height = frontend.get_window_height();
        let width = frontend.get_window_width();

        let mut buffers = Vec::new();
        let buffer = Buffer::from(source);

        buffers.push(Arc::new(Mutex::new(buffer)));

        let view = View::new(buffers[0].clone(), width, height);
        Editor {
            buffers: buffers,
            view: view,
            running: true,
            frontend: frontend,
            mode: mode,
        }
    }

    /// Handle key events
    ///
    /// Key events can be handled in an Overlay, OR in the current Mode.
    ///
    /// If there is an active Overlay, the key event is sent there, which gives
    /// back an OverlayEvent. We then parse this OverlayEvent and determine if
    /// the Overlay is finished and can be cleared. The response from the
    /// Overlay is then converted to a Command and sent off to be handled.
    ///
    /// If there is no active Overlay, the key event is sent to the current
    /// Mode, which returns a Command which we dispatch to handle_command.
    fn handle_key_event(&mut self, key: Option<Key>) {
        let key = match key {
            Some(k) => k,
            None => return
        };

        let mut remove_overlay = false;
        let command = match self.view.overlay {
            Overlay::None => self.mode.handle_key_event(key),
            _             => {
                let event = self.view.overlay.handle_key_event(key);
                match event {
                    OverlayEvent::Finished(response) => {
                        remove_overlay = true;
                        self.handle_overlay_response(response)
                    }

                    _ => { BuilderEvent::Incomplete }
                }
            }
        };

        if remove_overlay {
            self.view.overlay = Overlay::None;
            self.view.clear(&mut self.frontend);
        }

        if let BuilderEvent::Complete(c) = command {
            self.handle_command(c);
        }
    }

    /// Translate the response from an Overlay to a Command wrapped in a BuilderEvent
    ///
    /// In most cases, we will just want to convert the response directly to
    /// a Command, however in some cases we will want to perform other actions
    /// first, such as in the case of Overlay::SavePrompt.
    fn handle_overlay_response(&mut self, response: Option<String>) -> BuilderEvent {
        // FIXME: This entire method neext to be updated
        match response {
            Some(data) => {
                match self.view.overlay {

                    // FIXME: this is just a temporary fix
                    Overlay::Prompt { ref data, .. } => {
                        match &**data {
                            // FIXME: need to find a better system for these commands
                            //        They should be chainable
                            //          ie: wq - save & quit
                            //        They should also take arguments
                            //          ie w file.txt - write buffer to file.txt
                            "q" | "quit" => BuilderEvent::Complete(Command::exit_editor()),
                            "w" | "write" => BuilderEvent::Complete(Command::save_buffer()),

                            _ => BuilderEvent::Incomplete
                        }
                    }

                    Overlay::SavePrompt { .. } => {
                        if data.len() > 0 {
                            let path = PathBuf::from(&*data);
                            self.view.buffer.lock().unwrap().file_path = Some(path);
                            BuilderEvent::Complete(Command::save_buffer())
                        } else {
                            BuilderEvent::Invalid
                        }
                    }

                    Overlay::SelectFile { .. } => {
                        let path = PathBuf::from(data);
                        let buffer = Arc::new(Mutex::new(Buffer::from(path)));
                        self.buffers.push(buffer.clone());
                        self.view.set_buffer(buffer.clone());
                        self.view.clear(&mut self.frontend);
                        BuilderEvent::Complete(Command::noop())
                    }

                    _ => BuilderEvent::Incomplete,
                }
            }
            None => BuilderEvent::Incomplete
        }
    }

    /// Handle resize events
    ///
    /// width and height represent the new height of the window.
    fn handle_resize_event(&mut self, width: usize, height: usize) {
        self.view.resize(width, height);
    }

    /// Draw the current view to the frontend
    fn draw(&mut self) {
        self.view.draw(&mut self.frontend);
    }

    /// Handle the given command, performing the associated action
    fn handle_command(&mut self, command: Command) {
        let repeat = if command.number > 0 {
            command.number
        } else { 1 };
        for _ in 0..repeat {
            match command.action {
                Action::Instruction(i) => self.handle_instruction(i, command),
                Action::Operation(o) => self.handle_operation(o, command),
            }
        }
    }

    fn handle_instruction(&mut self, instruction: Instruction, command: Command) {
        match instruction {
            Instruction::SaveBuffer => { self.view.try_save_buffer() }
            Instruction::ExitEditor => { self.running = false; }
            Instruction::SetMark(mark) => {
                if let Some(object) = command.object {
                    self.view.move_mark(mark, object)
                }
            }
            Instruction::SetOverlay(overlay_type) => {
                self.view.set_overlay(overlay_type)
            }
            Instruction::SetMode(mode) => {
                match mode {
                    ModeType::Insert => { self.mode = Box::new(InsertMode::new()) }
                    ModeType::Normal => { self.mode = Box::new(NormalMode::new()) }
                }
            }
            Instruction::SwitchToLastBuffer => {
                self.view.switch_last_buffer();
                self.view.clear(&mut self.frontend);
            }

            _ => {}
        }
    }

    fn handle_operation(&mut self, operation: Operation, command: Command) {
        match operation {
            Operation::Insert(c) => {
                for _ in 0..command.number {
                    self.view.insert_char(c)
                }
            }
            Operation::DeleteObject => {
                if let Some(obj) = command.object {
                    self.view.delete_object(obj);
                }
            }
            Operation::DeleteFromMark(m) => {
                if command.object.is_some() {
                    self.view.delete_from_mark_to_object(m, command.object.unwrap())
                }
            }
            Operation::Undo => { self.view.undo() }
            Operation::Redo => { self.view.redo() }
        }
    }

    /// Start Iota!
    pub fn start(&mut self) {
        while self.running {
            self.draw();
            self.frontend.present();
            let event = self.frontend.poll_event();

            match event {
                EditorEvent::KeyEvent(key)         => self.handle_key_event(key),
                EditorEvent::Resize(width, height) => self.handle_resize_event(width, height),

                _ => {}
            }
        }
    }
}
<|endoftext|>