<commit_before>//
// sprocketnes/mapper.rs
//
// Copyright (c) 2013 Mozilla Foundation
// Author: Patrick Walton
//

use mem::Mem;
use rom::Rom;

pub struct Mapper {
    rom: &Rom,

    // FIXME: ~fn is awful here; we need the function region work.
    // FIXME: We should trait-ify this. It's hard because of the region in Rom though. I guess we
    // need region-parameterized &Traits to fix this. Dependent on the function region work.
    // NB: This exposed a nasty Rust bug! ~IMapper segfaults; see "segfault" branch.
    loadb: ~fn(this: &mut Mapper, addr: u16) -> u8,
    storeb: ~fn(this: &mut Mapper, addr: u16, val: u8),
}

pub impl Mapper {
    static fn new(rom: &a/Rom) -> Mapper/&a {
        match rom.header.mapper() {
            0 => Mapper {
                rom: rom,
                loadb:  |this, addr|      Nrom.loadb(this, addr),
                storeb: |this, addr, val| Nrom.storeb(this, addr, val),
            },
            _ => fail ~"unsupported mapper"
        }
    }
}

//
// Mapper 0 (NROM)
//
// See http://wiki.nesdev.com/w/index.php/NROM
//

// TODO: RAM.
pub struct Nrom;

// TODO: Support 32K ROMs (NROM-256).
pub impl Nrom {
    fn loadb(self, this: &mut Mapper, addr: u16) -> u8 {
        if addr <= 0x8000 {
            0   // FIXME
        } else {
            // FIXME: Unsafe get for speed?
            this.rom.prg[addr & 0x3fff]
        }
    }
    fn storeb(self, _: &mut Mapper, _: u16, _: u8) {
        // TODO
    }
}

<commit_msg>Handle 32K NROMs properly<commit_after>//
// sprocketnes/mapper.rs
//
// Copyright (c) 2013 Mozilla Foundation
// Author: Patrick Walton
//

use mem::Mem;
use rom::Rom;

pub struct Mapper {
    rom: &Rom,

    // FIXME: ~fn is awful here; we need the function region work.
    // FIXME: We should trait-ify this. It's hard because of the region in Rom though. I guess we
    // need region-parameterized &Traits to fix this. Dependent on the function region work.
    // NB: This exposed a nasty Rust bug! ~IMapper segfaults; see "segfault" branch.
    loadb: ~fn(this: &mut Mapper, addr: u16) -> u8,
    storeb: ~fn(this: &mut Mapper, addr: u16, val: u8),
}

pub impl Mapper {
    static fn new(rom: &a/Rom) -> Mapper/&a {
        match rom.header.mapper() {
            0 => Mapper {
                rom: rom,
                loadb:  |this, addr|      Nrom.loadb(this, addr),
                storeb: |this, addr, val| Nrom.storeb(this, addr, val),
            },
            _ => fail ~"unsupported mapper"
        }
    }
}

//
// Mapper 0 (NROM)
//
// See http://wiki.nesdev.com/w/index.php/NROM
//

// TODO: RAM.
pub struct Nrom;

pub impl Nrom {
    fn loadb(self, this: &mut Mapper, addr: u16) -> u8 {
        if addr < 0x8000 {
            0   // FIXME
        } else {
            // FIXME: Unsafe get for speed?
            if this.rom.prg.len() > 16384 {
                this.rom.prg[addr & 0x7fff]
            } else {
                this.rom.prg[addr & 0x3fff]
            }
        }
    }
    fn storeb(self, _: &mut Mapper, _: u16, _: u8) {
        // TODO
    }
}

<|endoftext|>


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

use std::cmp::ApproxEq;
use std::num;
use std::num::{NumCast, One, Zero};

pub fn Matrix4<T:Add<T,T> + Clone + ApproxEq<T> + Mul<T,T> + One + Zero>(
        m11: T, m12: T, m13: T, m14: T,
        m21: T, m22: T, m23: T, m24: T,
        m31: T, m32: T, m33: T, m34: T,
        m41: T, m42: T, m43: T, m44: T)
     -> Matrix4<T> {
    Matrix4 {
        m11: m11, m12: m12, m13: m13, m14: m14,
        m21: m21, m22: m22, m23: m23, m24: m24,
        m31: m31, m32: m32, m33: m33, m34: m34,
        m41: m41, m42: m42, m43: m43, m44: m44
    }
}

pub struct Matrix4<T> {
    m11: T, m12: T, m13: T, m14: T,
    m21: T, m22: T, m23: T, m24: T,
    m31: T, m32: T, m33: T, m34: T,
    m41: T, m42: T, m43: T, m44: T,
}

impl<T:Add<T,T> + Clone + ApproxEq<T> + Mul<T,T> + One + Zero> Matrix4<T> {
    pub fn approx_eq(&self, other: &Matrix4<T>) -> bool {
        self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
        self.m13.approx_eq(&other.m13) && self.m14.approx_eq(&other.m14) &&
        self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
        self.m23.approx_eq(&other.m23) && self.m24.approx_eq(&other.m24) &&
        self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32) &&
        self.m33.approx_eq(&other.m33) && self.m34.approx_eq(&other.m34) &&
        self.m41.approx_eq(&other.m41) && self.m42.approx_eq(&other.m42) &&
        self.m43.approx_eq(&other.m43) && self.m44.approx_eq(&other.m44)
    }

    pub fn mul(&self, m: &Matrix4<T>) -> Matrix4<T> {
        Matrix4(m.m11*self.m11 + m.m12*self.m21 + m.m13*self.m31 + m.m14*self.m41,
                m.m11*self.m12 + m.m12*self.m22 + m.m13*self.m32 + m.m14*self.m42,
                m.m11*self.m13 + m.m12*self.m23 + m.m13*self.m33 + m.m14*self.m43,
                m.m11*self.m14 + m.m12*self.m24 + m.m13*self.m34 + m.m14*self.m44,
                m.m21*self.m11 + m.m22*self.m21 + m.m23*self.m31 + m.m24*self.m41,
                m.m21*self.m12 + m.m22*self.m22 + m.m23*self.m32 + m.m24*self.m42,
                m.m21*self.m13 + m.m22*self.m23 + m.m23*self.m33 + m.m24*self.m43,
                m.m21*self.m14 + m.m22*self.m24 + m.m23*self.m34 + m.m24*self.m44,
                m.m31*self.m11 + m.m32*self.m21 + m.m33*self.m31 + m.m34*self.m41,
                m.m31*self.m12 + m.m32*self.m22 + m.m33*self.m32 + m.m34*self.m42,
                m.m31*self.m13 + m.m32*self.m23 + m.m33*self.m33 + m.m34*self.m43,
                m.m31*self.m14 + m.m32*self.m24 + m.m33*self.m34 + m.m34*self.m44,
                m.m41*self.m11 + m.m42*self.m21 + m.m43*self.m31 + m.m44*self.m41,
                m.m41*self.m12 + m.m42*self.m22 + m.m43*self.m32 + m.m44*self.m42,
                m.m41*self.m13 + m.m42*self.m23 + m.m43*self.m33 + m.m44*self.m43,
                m.m41*self.m14 + m.m42*self.m24 + m.m43*self.m34 + m.m44*self.m44)
    }

    pub fn mul_s(&self, x: T) -> Matrix4<T> {
        Matrix4(self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x,
                self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x,
                self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x,
                self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x)
    }

    pub fn scale(&self, x: T, y: T, z: T) -> Matrix4<T> {
        Matrix4(self.m11 * x,     self.m12.clone(), self.m13.clone(), self.m14.clone(),
                self.m21.clone(), self.m22 * y,     self.m23.clone(), self.m24.clone(),
                self.m31.clone(), self.m32.clone(), self.m33 * z,     self.m34.clone(),
                self.m41.clone(), self.m42.clone(), self.m43.clone(), self.m44.clone())
    }

    pub fn to_array(&self) -> [T, ..16] {
        [
            self.m11.clone(), self.m12.clone(), self.m13.clone(), self.m14.clone(),
            self.m21.clone(), self.m22.clone(), self.m23.clone(), self.m24.clone(),
            self.m31.clone(), self.m32.clone(), self.m33.clone(), self.m34.clone(),
            self.m41.clone(), self.m42.clone(), self.m43.clone(), self.m44.clone()
        ]
    }

    pub fn translate(&self, x: T, y: T, z: T) -> Matrix4<T> {
        let (_0, _1): (T, T) = (Zero::zero(), One::one());
        let matrix = Matrix4(_1.clone(), _0.clone(), _0.clone(), _0.clone(),
                             _0.clone(), _1.clone(), _0.clone(), _0.clone(),
                             _0.clone(), _0.clone(), _1.clone(), _0.clone(),
                             x,  y,  z,  _1.clone());

        return self.mul(&matrix);
    }
}

pub fn ortho<T:Add<T,T> + Clone + Div<T,T> + ApproxEq<T> + Mul<T,T> + Neg<T> + NumCast + One +
               Sub<T,T> + Zero>
        (left: T,
         right: T,
         bottom: T,
         top: T,
         near: T,
         far: T)
      -> Matrix4<T> {
    let _2: T = num::cast(2);
    let _1: T = One::one();
    let _0: T = Zero::zero();

    let tx = -((right + left) / (right - left));
    let ty = -((top + bottom) / (top - bottom));
    let tz = -((far + near) / (far - near));

    Matrix4(_2 / (right - left), _0.clone(),          _0.clone(),         _0.clone(),
            _0.clone(),          _2 / (top - bottom), _0.clone(),         _0.clone(),
            _0.clone(),          _0.clone(),          -_2 / (far - near), _0.clone(),
            tx,                  ty,                  tz,                 _1.clone())
}

pub fn identity<T:Add<T,T> + Clone + ApproxEq<T> + Mul<T,T> + One + Zero>() -> Matrix4<T> {
    let (_0, _1): (T, T) = (Zero::zero(), One::one());
    Matrix4(_1.clone(), _0.clone(), _0.clone(), _0.clone(),
            _0.clone(), _1.clone(), _0.clone(), _0.clone(),
            _0.clone(), _0.clone(), _1.clone(), _0.clone(),
            _0.clone(), _0.clone(), _0.clone(), _1.clone())
}

#[test]
pub fn test_ortho() {
    let (left, right, bottom, top) = (0.0, 1.0, 0.1, 1.0);
    let (near, far) = (-1.0, 1.0);
    let result = ortho(left, right, bottom, top, near, far);
    let expected = Matrix4(2.0,  0.0,         0.0,  0.0,
                           0.0,  2.22222222,  0.0,  0.0,
                           0.0,  0.0,         -1.0, 0.0,
                           -1.0, -1.22222222, -0.0, 1.0);
    debug!("result=%? expected=%?", result, expected);
    assert!(result.approx_eq(&expected));
}

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

use std::cmp::ApproxEq;
use std::num;
use std::num::{NumCast, One, Zero};

pub fn Matrix4<T:Add<T,T> + Clone + ApproxEq<T> + Mul<T,T> + One + Zero>(
        m11: T, m12: T, m13: T, m14: T,
        m21: T, m22: T, m23: T, m24: T,
        m31: T, m32: T, m33: T, m34: T,
        m41: T, m42: T, m43: T, m44: T)
     -> Matrix4<T> {
    Matrix4 {
        m11: m11, m12: m12, m13: m13, m14: m14,
        m21: m21, m22: m22, m23: m23, m24: m24,
        m31: m31, m32: m32, m33: m33, m34: m34,
        m41: m41, m42: m42, m43: m43, m44: m44
    }
}

pub struct Matrix4<T> {
    m11: T, m12: T, m13: T, m14: T,
    m21: T, m22: T, m23: T, m24: T,
    m31: T, m32: T, m33: T, m34: T,
    m41: T, m42: T, m43: T, m44: T,
}

impl<T:Add<T,T> + Clone + ApproxEq<T> + Mul<T,T> + One + Zero> Matrix4<T> {
    pub fn approx_eq(&self, other: &Matrix4<T>) -> bool {
        self.m11.approx_eq(&other.m11) && self.m12.approx_eq(&other.m12) &&
        self.m13.approx_eq(&other.m13) && self.m14.approx_eq(&other.m14) &&
        self.m21.approx_eq(&other.m21) && self.m22.approx_eq(&other.m22) &&
        self.m23.approx_eq(&other.m23) && self.m24.approx_eq(&other.m24) &&
        self.m31.approx_eq(&other.m31) && self.m32.approx_eq(&other.m32) &&
        self.m33.approx_eq(&other.m33) && self.m34.approx_eq(&other.m34) &&
        self.m41.approx_eq(&other.m41) && self.m42.approx_eq(&other.m42) &&
        self.m43.approx_eq(&other.m43) && self.m44.approx_eq(&other.m44)
    }

    pub fn mul(&self, m: &Matrix4<T>) -> Matrix4<T> {
        Matrix4(m.m11*self.m11 + m.m12*self.m21 + m.m13*self.m31 + m.m14*self.m41,
                m.m11*self.m12 + m.m12*self.m22 + m.m13*self.m32 + m.m14*self.m42,
                m.m11*self.m13 + m.m12*self.m23 + m.m13*self.m33 + m.m14*self.m43,
                m.m11*self.m14 + m.m12*self.m24 + m.m13*self.m34 + m.m14*self.m44,
                m.m21*self.m11 + m.m22*self.m21 + m.m23*self.m31 + m.m24*self.m41,
                m.m21*self.m12 + m.m22*self.m22 + m.m23*self.m32 + m.m24*self.m42,
                m.m21*self.m13 + m.m22*self.m23 + m.m23*self.m33 + m.m24*self.m43,
                m.m21*self.m14 + m.m22*self.m24 + m.m23*self.m34 + m.m24*self.m44,
                m.m31*self.m11 + m.m32*self.m21 + m.m33*self.m31 + m.m34*self.m41,
                m.m31*self.m12 + m.m32*self.m22 + m.m33*self.m32 + m.m34*self.m42,
                m.m31*self.m13 + m.m32*self.m23 + m.m33*self.m33 + m.m34*self.m43,
                m.m31*self.m14 + m.m32*self.m24 + m.m33*self.m34 + m.m34*self.m44,
                m.m41*self.m11 + m.m42*self.m21 + m.m43*self.m31 + m.m44*self.m41,
                m.m41*self.m12 + m.m42*self.m22 + m.m43*self.m32 + m.m44*self.m42,
                m.m41*self.m13 + m.m42*self.m23 + m.m43*self.m33 + m.m44*self.m43,
                m.m41*self.m14 + m.m42*self.m24 + m.m43*self.m34 + m.m44*self.m44)
    }

    pub fn mul_s(&self, x: T) -> Matrix4<T> {
        Matrix4(self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x,
                self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x,
                self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x,
                self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x)
    }

    pub fn scale(&self, x: T, y: T, z: T) -> Matrix4<T> {
        Matrix4(self.m11 * x,     self.m12.clone(), self.m13.clone(), self.m14.clone(),
                self.m21.clone(), self.m22 * y,     self.m23.clone(), self.m24.clone(),
                self.m31.clone(), self.m32.clone(), self.m33 * z,     self.m34.clone(),
                self.m41.clone(), self.m42.clone(), self.m43.clone(), self.m44.clone())
    }

    pub fn to_array(&self) -> [T, ..16] {
        [
            self.m11.clone(), self.m12.clone(), self.m13.clone(), self.m14.clone(),
            self.m21.clone(), self.m22.clone(), self.m23.clone(), self.m24.clone(),
            self.m31.clone(), self.m32.clone(), self.m33.clone(), self.m34.clone(),
            self.m41.clone(), self.m42.clone(), self.m43.clone(), self.m44.clone()
        ]
    }

    pub fn translate(&self, x: T, y: T, z: T) -> Matrix4<T> {
        let (_0, _1): (T, T) = (Zero::zero(), One::one());
        let matrix = Matrix4(_1.clone(), _0.clone(), _0.clone(), _0.clone(),
                             _0.clone(), _1.clone(), _0.clone(), _0.clone(),
                             _0.clone(), _0.clone(), _1.clone(), _0.clone(),
                             x,  y,  z,  _1.clone());

        return self.mul(&matrix);
    }
}

pub fn ortho<T:Add<T,T> + Clone + Div<T,T> + ApproxEq<T> + Mul<T,T> + Neg<T> + NumCast + One +
               Sub<T,T> + Zero>
        (left: T,
         right: T,
         bottom: T,
         top: T,
         near: T,
         far: T)
      -> Matrix4<T> {
    let _2: T = num::cast(2).unwrap();
    let _1: T = One::one();
    let _0: T = Zero::zero();

    let tx = -((right + left) / (right - left));
    let ty = -((top + bottom) / (top - bottom));
    let tz = -((far + near) / (far - near));

    Matrix4(_2 / (right - left), _0.clone(),          _0.clone(),         _0.clone(),
            _0.clone(),          _2 / (top - bottom), _0.clone(),         _0.clone(),
            _0.clone(),          _0.clone(),          -_2 / (far - near), _0.clone(),
            tx,                  ty,                  tz,                 _1.clone())
}

pub fn identity<T:Add<T,T> + Clone + ApproxEq<T> + Mul<T,T> + One + Zero>() -> Matrix4<T> {
    let (_0, _1): (T, T) = (Zero::zero(), One::one());
    Matrix4(_1.clone(), _0.clone(), _0.clone(), _0.clone(),
            _0.clone(), _1.clone(), _0.clone(), _0.clone(),
            _0.clone(), _0.clone(), _1.clone(), _0.clone(),
            _0.clone(), _0.clone(), _0.clone(), _1.clone())
}

#[test]
pub fn test_ortho() {
    let (left, right, bottom, top) = (0.0, 1.0, 0.1, 1.0);
    let (near, far) = (-1.0, 1.0);
    let result = ortho(left, right, bottom, top, near, far);
    let expected = Matrix4(2.0,  0.0,         0.0,  0.0,
                           0.0,  2.22222222,  0.0,  0.0,
                           0.0,  0.0,         -1.0, 0.0,
                           -1.0, -1.22222222, -0.0, 1.0);
    debug!("result=%? expected=%?", result, expected);
    assert!(result.approx_eq(&expected));
}

<|endoftext|>


<commit_before>use vec3::Vec3;
use pointlight::PointLight;
use sphere::Sphere;
use plane::Plane;
use flatmaterial::FlatMaterial;
use light::Light;
use prim::Prim;

mod vec3;
mod ray;
mod camera;
mod prim;
mod sphere;
mod plane;
mod light;
mod pointlight;
mod material;
mod flatmaterial;
mod intersection;
mod scene;
mod renderer;
mod export;

fn main() {
    let image_width = 50;
    let image_height = 50;

    let max_lights = 10;
    let max_prims = 1000;

    let mut lights: Vec<Box<Light>> = Vec::with_capacity(max_lights);
    lights.push(box PointLight {position: Vec3 {x: 50.0, y: 90.0, z: 50.0}, color: Vec3 {x: 1.0, y: 1.0, z: 1.0}});

    let grey1 = box FlatMaterial {color: Vec3 {x: 0.6, y: 0.6, z: 0.6}};
    let grey2 = box FlatMaterial {color: Vec3 {x: 0.6, y: 0.6, z: 0.6}};
    let grey3 = box FlatMaterial {color: Vec3 {x: 0.6, y: 0.6, z: 0.6}};
    let red   = box FlatMaterial {color: Vec3 {x: 1.0, y: 0.0, z: 0.0}};
    let green = box FlatMaterial {color: Vec3 {x: 0.0, y: 1.0, z: 0.0}};

    let blue1   = box FlatMaterial {color: Vec3 {x: 0.0, y: 0.0, z: 1.0}};
    let blue2   = box FlatMaterial {color: Vec3 {x: 0.3, y: 0.3, z: 1.0}};

    let mut prims: Vec<Box<Prim>> = Vec::with_capacity(max_prims);
    prims.push(box Plane {a: 0.0,  b:  0.0, c: 1.0, d: 0.0,   material: grey1 }); // Ahead
    prims.push(box Plane {a: 0.0,  b: -1.0, c: 0.0, d: 100.0, material: grey2 }); // Bottom
    prims.push(box Plane {a: 0.0,  b:  1.0, c: 0.0, d: 0.0,   material: grey3 }); // Top
    prims.push(box Plane {a: 1.0,  b:  0.0, c: 0.0, d: 0.0,   material: red   }); // Left
    prims.push(box Plane {a: -1.0, b:  0.0, c: 0.0, d: 100.0, material: green }); // Right

    prims.push(box Sphere {center: Vec3 {x: 30.0, y: 15.0, z: 20.0}, radius: 15.0, material: blue1});
    prims.push(box Sphere {center: Vec3 {x: 70.0, y: 17.0, z: 80.0}, radius: 17.0, material: blue2});

    let camera = camera::Camera::new(
        Vec3 {x: 50.0, y: 25.0, z: 300.0},
        Vec3 {x: 50.0, y: 50.0, z: 50.0},
        Vec3 {x: 0.0, y: 1.0, z: 0.0},
        45.0,
        image_width,
        image_height
    );

    let scene = scene::Scene {
        lights: lights,
        prims: prims,
        background: Vec3 {x: 1.0, y: 1.0, z: 1.0}
    };

    let renderer = renderer::Renderer {
        reflect_depth: 2,
        refract_depth: 4,
        use_octree: false,
        shadows: false,
        threads: 1
    };
    let image_data = renderer.render(camera, scene);

    ::export::to_ppm(image_data, image_width, image_height, "test.ppm");
}
<commit_msg>Cleaner materials for main<commit_after>use vec3::Vec3;
use pointlight::PointLight;
use sphere::Sphere;
use plane::Plane;
use flatmaterial::FlatMaterial;
use light::Light;
use prim::Prim;

mod vec3;
mod ray;
mod camera;
mod prim;
mod sphere;
mod plane;
mod light;
mod pointlight;
mod material;
mod flatmaterial;
mod intersection;
mod scene;
mod renderer;
mod export;

fn main() {
    let image_width = 50;
    let image_height = 50;

    let max_lights = 10;
    let max_prims = 1000;

    let mut lights: Vec<Box<Light>> = Vec::with_capacity(max_lights);
    lights.push(box PointLight {position: Vec3 {x: 50.0, y: 90.0, z: 50.0}, color: Vec3 {x: 1.0, y: 1.0, z: 1.0}});

    let grey  = FlatMaterial {color: Vec3 {x: 0.6, y: 0.6, z: 0.6}};
    let red   = FlatMaterial {color: Vec3 {x: 1.0, y: 0.0, z: 0.0}};
    let green = FlatMaterial {color: Vec3 {x: 0.0, y: 1.0, z: 0.0}};
    let blue  = FlatMaterial {color: Vec3 {x: 0.0, y: 0.0, z: 1.0}};

    let mut prims: Vec<Box<Prim>> = Vec::with_capacity(max_prims);
    prims.push(box Plane {a: 0.0,  b:  0.0, c: 1.0, d: 0.0,   material: box grey }); // Ahead
    prims.push(box Plane {a: 0.0,  b: -1.0, c: 0.0, d: 100.0, material: box grey }); // Bottom
    prims.push(box Plane {a: 0.0,  b:  1.0, c: 0.0, d: 0.0,   material: box grey }); // Top
    prims.push(box Plane {a: 1.0,  b:  0.0, c: 0.0, d: 0.0,   material: box red   }); // Left
    prims.push(box Plane {a: -1.0, b:  0.0, c: 0.0, d: 100.0, material: box green }); // Right

    prims.push(box Sphere {center: Vec3 {x: 30.0, y: 15.0, z: 20.0}, radius: 15.0, material: box blue});
    prims.push(box Sphere {center: Vec3 {x: 70.0, y: 17.0, z: 80.0}, radius: 17.0, material: box blue});

    let camera = camera::Camera::new(
        Vec3 {x: 50.0, y: 25.0, z: 300.0},
        Vec3 {x: 50.0, y: 50.0, z: 50.0},
        Vec3 {x: 0.0, y: 1.0, z: 0.0},
        45.0,
        image_width,
        image_height
    );

    let scene = scene::Scene {
        lights: lights,
        prims: prims,
        background: Vec3 {x: 1.0, y: 1.0, z: 1.0}
    };

    let renderer = renderer::Renderer {
        reflect_depth: 2,
        refract_depth: 4,
        use_octree: false,
        shadows: false,
        threads: 1
    };
    let image_data = renderer.render(camera, scene);

    ::export::to_ppm(image_data, image_width, image_height, "test.ppm");
}
<|endoftext|>


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

use num_lib;
use std::cmp::{self, max, min};
use std::fmt;
use std::iter;
use std::marker::PhantomData;
use std::num;
use std::ops;

pub trait Int:
    Copy
    + ops::Add<Self, Output=Self>
    + ops::Sub<Self, Output=Self>
    + cmp::Ord
{
    fn zero() -> Self;
    fn one() -> Self;
    fn max_value() -> Self;
    fn from_usize(n: usize) -> Option<Self>;
}
impl Int for isize {
    fn zero() -> isize { 0 }
    fn one() -> isize { 1 }
    fn max_value() -> isize { ::std::isize::MAX }
    fn from_usize(n: usize) -> Option<isize> { num_lib::NumCast::from(n) }
}
impl Int for usize {
    fn zero() -> usize { 0 }
    fn one() -> usize { 1 }
    fn max_value() -> usize { ::std::usize::MAX }
    fn from_usize(n: usize) -> Option<usize> { Some(n) }
}

/// An index type to be used by a `Range`
pub trait RangeIndex: Int + fmt::Debug {
    type Index;
    fn new(x: Self::Index) -> Self;
    fn get(self) -> Self::Index;
}

impl RangeIndex for isize {
    type Index = isize;
    #[inline]
    fn new(x: isize) -> isize { x }

    #[inline]
    fn get(self) -> isize { self }
}

impl RangeIndex for usize {
    type Index = usize;
    #[inline]
    fn new(x: usize) -> usize { x }

    #[inline]
    fn get(self) -> usize { self }
}

/// Implements a range index type with operator overloads
#[macro_export]
macro_rules! int_range_index {
    ($(#[$attr:meta])* struct $Self_:ident($T:ty)) => (
        #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Copy)]
        $(#[$attr])*
        pub struct $Self_(pub $T);

        impl $Self_ {
            #[inline]
            pub fn to_usize(self) -> usize {
                self.get() as usize
            }
        }

        impl RangeIndex for $Self_ {
            type Index = $T;
            #[inline]
            fn new(x: $T) -> $Self_ {
                $Self_(x)
            }

            #[inline]
            fn get(self) -> $T {
                match self { $Self_(x) => x }
            }
        }

        impl $crate::range::Int for $Self_ {
            fn zero() -> $Self_ { $Self_($crate::range::Int::zero()) }
            fn one() -> $Self_ { $Self_($crate::range::Int::one()) }
            fn max_value() -> $Self_ { $Self_($crate::range::Int::max_value()) }
            fn from_usize(n: usize) -> Option<$Self_> { $crate::range::Int::from_usize(n).map($Self_) }
        }

        impl ::std::ops::Add<$Self_> for $Self_ {
            type Output = $Self_;

            #[inline]
            fn add(self, other: $Self_) -> $Self_ {
                $Self_(self.get() + other.get())
            }
        }

        impl ::std::ops::Sub<$Self_> for $Self_ {
            type Output = $Self_;

            #[inline]
            fn sub(self, other: $Self_) -> $Self_ {
                $Self_(self.get() - other.get())
            }
        }

        impl ::std::ops::Neg for $Self_ {
            type Output = $Self_;

            #[inline]
            fn neg(self) -> $Self_ {
                $Self_(-self.get())
            }
        }
    )
}

/// A range of indices
#[derive(Clone, RustcEncodable, Copy, Deserialize, Serialize)]
pub struct Range<I> {
    begin: I,
    length: I,
}

impl<I: RangeIndex> fmt::Debug for Range<I> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{:?} .. {:?})", self.begin(), self.end())
    }
}

/// An iterator over each index in a range
pub struct EachIndex<T, I> {
    it: ops::Range<T>,
    phantom: PhantomData<I>,
}

pub fn each_index<T: Int, I: RangeIndex<Index=T>>(start: I, stop: I) -> EachIndex<T, I> {
    EachIndex { it: start.get()..stop.get(), phantom: PhantomData }
}

impl<T: Int, I: RangeIndex<Index=T>> Iterator for EachIndex<T, I>
where T: Int + num::One + iter::Step, for<'a> &'a T: ops::Add<&'a T, Output = T> {
    type Item = I;

    #[inline]
    fn next(&mut self) -> Option<I> {
        self.it.next().map(RangeIndex::new)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.it.size_hint()
    }
}

impl<I: RangeIndex> Range<I> {
    /// Create a new range from beginning and length offsets. This could be
    /// denoted as `[begin, begin + length)`.
    ///
    /// ~~~ignore
    ///    |-- begin ->|-- length ->|
    ///    |           |            |
    /// <- o - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn new(begin: I, length: I) -> Range<I> {
        Range { begin: begin, length: length }
    }

    #[inline]
    pub fn empty() -> Range<I> {
        Range::new(Int::zero(), Int::zero())
    }

    /// The index offset to the beginning of the range.
    ///
    /// ~~~ignore
    ///    |-- begin ->|
    ///    |           |
    /// <- o - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn begin(&self) -> I { self.begin  }

    /// The index offset from the beginning to the end of the range.
    ///
    /// ~~~ignore
    ///                |-- length ->|
    ///                |            |
    /// <- o - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn length(&self) -> I { self.length }

    /// The index offset to the end of the range.
    ///
    /// ~~~ignore
    ///    |--------- end --------->|
    ///    |                        |
    /// <- o - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn end(&self) -> I { self.begin + self.length }

    /// `true` if the index is between the beginning and the end of the range.
    ///
    /// ~~~ignore
    ///        false        true      false
    ///          |           |          |
    /// <- o - - + - - +=====+======+ - + - ->
    /// ~~~
    #[inline]
    pub fn contains(&self, i: I) -> bool {
        i >= self.begin() && i < self.end()
    }

    /// `true` if the offset from the beginning to the end of the range is zero.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.length() == Int::zero()
    }

    /// Shift the entire range by the supplied index delta.
    ///
    /// ~~~ignore
    ///                     |-- delta ->|
    ///                     |           |
    /// <- o - +============+ - - - - - | - - - ->
    ///                                 |
    /// <- o - - - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn shift_by(&mut self, delta: I) {
        self.begin = self.begin + delta;
    }

    /// Extend the end of the range by the supplied index delta.
    ///
    /// ~~~ignore
    ///                     |-- delta ->|
    ///                     |           |
    /// <- o - - - - - +====+ - - - - - | - - - ->
    ///                                 |
    /// <- o - - - - - +================+ - - - ->
    /// ~~~
    #[inline]
    pub fn extend_by(&mut self, delta: I) {
        self.length = self.length + delta;
    }

    /// Move the end of the range to the target index.
    ///
    /// ~~~ignore
    ///                               target
    ///                                 |
    /// <- o - - - - - +====+ - - - - - | - - - ->
    ///                                 |
    /// <- o - - - - - +================+ - - - ->
    /// ~~~
    #[inline]
    pub fn extend_to(&mut self, target: I) {
        self.length = target - self.begin;
    }

    /// Adjust the beginning offset and the length by the supplied deltas.
    #[inline]
    pub fn adjust_by(&mut self, begin_delta: I, length_delta: I) {
        self.begin = self.begin + begin_delta;
        self.length = self.length + length_delta;
    }

    /// Set the begin and length values.
    #[inline]
    pub fn reset(&mut self, begin: I, length: I) {
        self.begin = begin;
        self.length = length;
    }

    #[inline]
    pub fn intersect(&self, other: &Range<I>) -> Range<I> {
        let begin = max(self.begin(), other.begin());
        let end = min(self.end(), other.end());

        if end < begin {
            Range::empty()
        } else {
            Range::new(begin, end - begin)
        }
    }
}

/// Methods for `Range`s with indices based on integer values
impl<T: Int, I: RangeIndex<Index=T>> Range<I> {
    /// Returns an iterater that increments over `[begin, end)`.
    #[inline]
    pub fn each_index(&self) -> EachIndex<T, I> {
        each_index(self.begin(), self.end())
    }

    #[inline]
    pub fn is_valid_for_string(&self, s: &str) -> bool {
        let s_len = s.len();
        match Int::from_usize(s_len) {
            Some(len) => {
                let len = RangeIndex::new(len);
                self.begin() < len
                && self.end() <= len
                && self.length() <= len
            },
            None => {
                debug!("Range<T>::is_valid_for_string: string length \
                        (len={:?}) is longer than the max value for the range \
                        index (max={:?})", s_len,
                        {
                            let max: T = Int::max_value();
                            let val: I = RangeIndex::new(max);
                            val
                        });
                false
            },
        }
    }
}
<commit_msg>Auto merge of #8440 - mbrubeck:range-unused, r=Manishearth<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use num_lib;
use std::cmp::{self, max, min};
use std::fmt;
use std::iter;
use std::marker::PhantomData;
use std::num;
use std::ops;

pub trait Int:
    Copy
    + ops::Add<Self, Output=Self>
    + ops::Sub<Self, Output=Self>
    + cmp::Ord
{
    fn zero() -> Self;
    fn one() -> Self;
    fn max_value() -> Self;
    fn from_usize(n: usize) -> Option<Self>;
}
impl Int for isize {
    fn zero() -> isize { 0 }
    fn one() -> isize { 1 }
    fn max_value() -> isize { ::std::isize::MAX }
    fn from_usize(n: usize) -> Option<isize> { num_lib::NumCast::from(n) }
}
impl Int for usize {
    fn zero() -> usize { 0 }
    fn one() -> usize { 1 }
    fn max_value() -> usize { ::std::usize::MAX }
    fn from_usize(n: usize) -> Option<usize> { Some(n) }
}

/// An index type to be used by a `Range`
pub trait RangeIndex: Int + fmt::Debug {
    type Index;
    fn new(x: Self::Index) -> Self;
    fn get(self) -> Self::Index;
}

impl RangeIndex for isize {
    type Index = isize;
    #[inline]
    fn new(x: isize) -> isize { x }

    #[inline]
    fn get(self) -> isize { self }
}

impl RangeIndex for usize {
    type Index = usize;
    #[inline]
    fn new(x: usize) -> usize { x }

    #[inline]
    fn get(self) -> usize { self }
}

/// Implements a range index type with operator overloads
#[macro_export]
macro_rules! int_range_index {
    ($(#[$attr:meta])* struct $Self_:ident($T:ty)) => (
        #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Copy)]
        $(#[$attr])*
        pub struct $Self_(pub $T);

        impl $Self_ {
            #[inline]
            pub fn to_usize(self) -> usize {
                self.get() as usize
            }
        }

        impl RangeIndex for $Self_ {
            type Index = $T;
            #[inline]
            fn new(x: $T) -> $Self_ {
                $Self_(x)
            }

            #[inline]
            fn get(self) -> $T {
                match self { $Self_(x) => x }
            }
        }

        impl $crate::range::Int for $Self_ {
            fn zero() -> $Self_ { $Self_($crate::range::Int::zero()) }
            fn one() -> $Self_ { $Self_($crate::range::Int::one()) }
            fn max_value() -> $Self_ { $Self_($crate::range::Int::max_value()) }
            fn from_usize(n: usize) -> Option<$Self_> { $crate::range::Int::from_usize(n).map($Self_) }
        }

        impl ::std::ops::Add<$Self_> for $Self_ {
            type Output = $Self_;

            #[inline]
            fn add(self, other: $Self_) -> $Self_ {
                $Self_(self.get() + other.get())
            }
        }

        impl ::std::ops::Sub<$Self_> for $Self_ {
            type Output = $Self_;

            #[inline]
            fn sub(self, other: $Self_) -> $Self_ {
                $Self_(self.get() - other.get())
            }
        }

        impl ::std::ops::Neg for $Self_ {
            type Output = $Self_;

            #[inline]
            fn neg(self) -> $Self_ {
                $Self_(-self.get())
            }
        }
    )
}

/// A range of indices
#[derive(Clone, RustcEncodable, Copy, Deserialize, Serialize)]
pub struct Range<I> {
    begin: I,
    length: I,
}

impl<I: RangeIndex> fmt::Debug for Range<I> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{:?} .. {:?})", self.begin(), self.end())
    }
}

/// An iterator over each index in a range
pub struct EachIndex<T, I> {
    it: ops::Range<T>,
    phantom: PhantomData<I>,
}

pub fn each_index<T: Int, I: RangeIndex<Index=T>>(start: I, stop: I) -> EachIndex<T, I> {
    EachIndex { it: start.get()..stop.get(), phantom: PhantomData }
}

impl<T: Int, I: RangeIndex<Index=T>> Iterator for EachIndex<T, I>
where T: Int + num::One + iter::Step, for<'a> &'a T: ops::Add<&'a T, Output = T> {
    type Item = I;

    #[inline]
    fn next(&mut self) -> Option<I> {
        self.it.next().map(RangeIndex::new)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        self.it.size_hint()
    }
}

impl<I: RangeIndex> Range<I> {
    /// Create a new range from beginning and length offsets. This could be
    /// denoted as `[begin, begin + length)`.
    ///
    /// ~~~ignore
    ///    |-- begin ->|-- length ->|
    ///    |           |            |
    /// <- o - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn new(begin: I, length: I) -> Range<I> {
        Range { begin: begin, length: length }
    }

    #[inline]
    pub fn empty() -> Range<I> {
        Range::new(Int::zero(), Int::zero())
    }

    /// The index offset to the beginning of the range.
    ///
    /// ~~~ignore
    ///    |-- begin ->|
    ///    |           |
    /// <- o - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn begin(&self) -> I { self.begin  }

    /// The index offset from the beginning to the end of the range.
    ///
    /// ~~~ignore
    ///                |-- length ->|
    ///                |            |
    /// <- o - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn length(&self) -> I { self.length }

    /// The index offset to the end of the range.
    ///
    /// ~~~ignore
    ///    |--------- end --------->|
    ///    |                        |
    /// <- o - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn end(&self) -> I { self.begin + self.length }

    /// `true` if the index is between the beginning and the end of the range.
    ///
    /// ~~~ignore
    ///        false        true      false
    ///          |           |          |
    /// <- o - - + - - +=====+======+ - + - ->
    /// ~~~
    #[inline]
    pub fn contains(&self, i: I) -> bool {
        i >= self.begin() && i < self.end()
    }

    /// `true` if the offset from the beginning to the end of the range is zero.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.length() == Int::zero()
    }

    /// Shift the entire range by the supplied index delta.
    ///
    /// ~~~ignore
    ///                     |-- delta ->|
    ///                     |           |
    /// <- o - +============+ - - - - - | - - - ->
    ///                                 |
    /// <- o - - - - - - - +============+ - - - ->
    /// ~~~
    #[inline]
    pub fn shift_by(&mut self, delta: I) {
        self.begin = self.begin + delta;
    }

    /// Extend the end of the range by the supplied index delta.
    ///
    /// ~~~ignore
    ///                     |-- delta ->|
    ///                     |           |
    /// <- o - - - - - +====+ - - - - - | - - - ->
    ///                                 |
    /// <- o - - - - - +================+ - - - ->
    /// ~~~
    #[inline]
    pub fn extend_by(&mut self, delta: I) {
        self.length = self.length + delta;
    }

    /// Move the end of the range to the target index.
    ///
    /// ~~~ignore
    ///                               target
    ///                                 |
    /// <- o - - - - - +====+ - - - - - | - - - ->
    ///                                 |
    /// <- o - - - - - +================+ - - - ->
    /// ~~~
    #[inline]
    pub fn extend_to(&mut self, target: I) {
        self.length = target - self.begin;
    }

    /// Adjust the beginning offset and the length by the supplied deltas.
    #[inline]
    pub fn adjust_by(&mut self, begin_delta: I, length_delta: I) {
        self.begin = self.begin + begin_delta;
        self.length = self.length + length_delta;
    }

    /// Set the begin and length values.
    #[inline]
    pub fn reset(&mut self, begin: I, length: I) {
        self.begin = begin;
        self.length = length;
    }

    #[inline]
    pub fn intersect(&self, other: &Range<I>) -> Range<I> {
        let begin = max(self.begin(), other.begin());
        let end = min(self.end(), other.end());

        if end < begin {
            Range::empty()
        } else {
            Range::new(begin, end - begin)
        }
    }
}

/// Methods for `Range`s with indices based on integer values
impl<T: Int, I: RangeIndex<Index=T>> Range<I> {
    /// Returns an iterater that increments over `[begin, end)`.
    #[inline]
    pub fn each_index(&self) -> EachIndex<T, I> {
        each_index(self.begin(), self.end())
    }
}
<|endoftext|>


<commit_before>extern crate xml;
extern crate regex;

use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io::BufReader;

use xml::reader::{EventReader, XmlEvent};
use xml::attribute::OwnedAttribute;

#[derive(Debug, Clone, Default)]
struct LineAttributes {
    top: i32,
    left: i32,
    height: i32,
    page: u32,
}

fn read_attributes(attr_list: &Vec<OwnedAttribute>) -> LineAttributes {
    let mut attributes : LineAttributes = Default::default();

    for attr in attr_list {
        match attr.name.local_name.as_ref() {
            "top" => attributes.top = attr.value.parse().unwrap(),
            "left" => attributes.left = attr.value.parse().unwrap(),
            "height" => attributes.height = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    attributes
}

#[derive(Debug, Clone, Default)]
struct ScriptProperties {
    direction_position: i32,
    dialog_position: i32,
    speaker_direction_position: i32,
    speaker_position: i32,
    intra_paragraph_line_height: i32,
}

fn read_and_analyze_script(reader: Box<Read>) -> (ScriptProperties, Vec<(LineAttributes, String)>) {
    let mut script_properties: ScriptProperties = Default::default();
    let mut lines: Vec<(LineAttributes, String)> = Vec::new();

    // these maps are used to heuristically determine the ScriptProperties
    let mut position_uses: HashMap<i32, u32> = HashMap::new();
    let mut line_height_uses: HashMap<i32, u32> = HashMap::new();

    // states for the streaming xml parsing
    let mut current_line_attributes: LineAttributes = Default::default();
    let mut current_text_buffer = String::new();
    let mut current_page_number = 0;
    let mut last_line_height = 0;

    let parser = EventReader::new(reader);
    for event in parser {
        match event {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                match name.local_name.as_ref() {
                    "text" => {
                        current_line_attributes = read_attributes(&attributes);

                        current_text_buffer.clear();

                        // increase the count for the current left margin
                        *position_uses.entry(current_line_attributes.left)
                                      .or_insert(0) += 1;

                        // increase the count for the current top position diff
                        *line_height_uses.entry(current_line_attributes.top - last_line_height)
                                         .or_insert(0) += 1;
                        last_line_height = current_line_attributes.top;
                    }
                    "page" => {
                        last_line_height = 0;

                        for attr in attributes {
                            if "number" == attr.name.local_name {
                                current_page_number = attr.value.parse().unwrap();
                                break;
                            }
                        }
                    }
                    _ => {}
                }
            }
            Ok(XmlEvent::Characters(text)) => {
                if current_text_buffer.len() > 0 {
                    current_text_buffer.push(' ');
                }
                current_text_buffer.push_str(text.trim());
            }
            Ok(XmlEvent::EndElement { name, .. }) => {
                if name.local_name == "text" {
                    current_line_attributes.page = current_page_number;
                    lines.push((current_line_attributes.clone(), current_text_buffer.clone()));
                }
            }
            Ok(_) => {},
            Err(e) => panic!("Error parsing xml: {}", e),
        }
    }

    // the position_uses map should at least have 3 different entries
    if position_uses.len() < 3 {
        panic!("Script uses strange layout");
    }

    // copy the position uses map into a vector and sort by value desc
    let mut position_uses_vec = position_uses.into_iter().collect::<Vec<_>>();
    position_uses_vec.sort_by(|&a, &b| b.1.cmp(&a.1));

    // sort the top 3 entries by position again (right-exclusive range)
    position_uses_vec[0..3].sort_by(|&a, &b| b.0.cmp(&a.0));

    script_properties.speaker_position = position_uses_vec[0].0;
    script_properties.dialog_position = position_uses_vec[1].0;
    script_properties.direction_position = position_uses_vec[2].0;

    // take the next value between speaker and dialog as speaker_direction
    for &value in position_uses_vec.iter().skip(3) {
        let (position, _) = value;
        if position > script_properties.dialog_position &&
           position < script_properties.speaker_position {
            script_properties.speaker_direction_position = position;
            break;
        }
    }

    // use to most used line diff value to determine the specific sections
    let mut last_uses: u32 = 0;
    for (&line_height, &uses) in line_height_uses.iter() {
        if uses > last_uses {
            script_properties.intra_paragraph_line_height = line_height;
            last_uses = uses;
        }
    }

    (script_properties, lines)
}

#[derive(Debug, Clone)]
enum DialogPart {
    Dialog(String),
    Direction(String),
}

#[derive(Debug, Clone)]
enum ScenePart {
    Direction {
        direction: String,
        page: u32,
    },
    Dialog {
        speaker: String,
        dialog: Vec<DialogPart>,
        page: u32,
    }
}

#[derive(Debug, Clone)]
enum ScriptPart {
    Separator,
    ScenePart(ScenePart),
    LocationChange(String),
    SceneChange,
}

fn is_location_change(line: &str) -> bool {
    line.starts_with("INT.") || line.starts_with("EXT.")
}

fn is_scene_change(line: &str) -> bool {
    line.starts_with("CUT TO")
}

fn extract_script_parts(properties: ScriptProperties, lines: &Vec<(LineAttributes, String)>)
    -> Vec<ScriptPart> {
    let mut script_parts: Vec<ScriptPart> = Vec::new();
    let mut last_top_position = 0;

    for line in lines.iter() {
        let &(ref attributes, ref line) = line;

        if line.len() == 0 {
            continue;
        }

        // check if a new section starts
        if attributes.top - last_top_position > 18 ||
           attributes.top - last_top_position < 0 {
            // used to separate two consecutive script parts of the
            // same type. this is just a implementation detail of
            // the parsing. the Separator can be ignored later.
            script_parts.push(ScriptPart::Separator);
        }

        if attributes.left == properties.direction_position {
            if is_location_change(line) {
                script_parts.push(ScriptPart::LocationChange(line.clone()));
            } else {
                // ensure the last script part is a direction
                if let Some(&ScriptPart::ScenePart(ScenePart::Direction{..})) = script_parts.last() {
                } else {
                    script_parts.push(ScriptPart::ScenePart(
                        ScenePart::Direction{
                            direction: String::new(),
                            page: attributes.page,
                        }));
                }

                if let Some(&mut ScriptPart::ScenePart(ScenePart::Direction{ref mut direction, ..})) = script_parts.last_mut() {
                    if direction.len() > 0 {
                        direction.push(' ');
                    }
                    direction.push_str(line);
                }
            }
        } else if attributes.left == properties.speaker_position ||
                  attributes.left == properties.speaker_direction_position ||
                  attributes.left == properties.dialog_position {
            // Ensure the last script part is a dialog
            if let Some(&ScriptPart::ScenePart(ScenePart::Dialog{..})) = script_parts.last() {
            } else {
                script_parts.push(ScriptPart::ScenePart(
                    ScenePart::Dialog{
                        speaker: String::new(),
                        dialog: Vec::new(),
                        page: attributes.page,
                    }));
            }

            // get the dialog, should never fail (see above)
            if let Some(&mut ScriptPart::ScenePart(ScenePart::Dialog{ref mut speaker, ref mut dialog, ..})) = script_parts.last_mut() {
                if attributes.left == properties.speaker_position {
                    // there is only one speaker per dialog
                    speaker.push_str(line);
                } else if attributes.left == properties.speaker_direction_position {
                    if let Some(&DialogPart::Direction(_)) = dialog.last() {
                    } else {
                        dialog.push(DialogPart::Direction(String::new()));
                    }

                    if let Some(&mut DialogPart::Direction(ref mut direction)) = dialog.last_mut() {
                        if direction.len() > 0 {
                            direction.push(' ');
                        }
                        direction.push_str(line);
                    }
                } else if attributes.left == properties.dialog_position {
                    if let Some(&DialogPart::Dialog(_)) = dialog.last() {
                    } else {
                        dialog.push(DialogPart::Dialog(String::new()));
                    }

                    if let Some(&mut DialogPart::Dialog(ref mut dialog)) = dialog.last_mut() {
                        if dialog.len() > 0 {
                            dialog.push(' ');
                        }
                        dialog.push_str(line);
                    }
                }
            }
        } else {
            if is_scene_change(line) {
                script_parts.push(ScriptPart::SceneChange);
            }
        }

        last_top_position = attributes.top;
    }

    script_parts
}

#[derive(Default, Clone, Debug)]
struct Location {
	internal: bool,
	name: String,
	parts: Vec<ScenePart>,
}

type Scene = Vec<Location>;

fn extract_scenes(script_parts: &Vec<ScriptPart>) -> Vec<Scene> {
	let mut scenes = Vec::new();

    // scene with default (empty) location
	let default_scene: Scene = vec![Default::default()];
	scenes.push(default_scene.clone());

	for script_part in script_parts.iter() {
		use ScriptPart::*;
		match script_part {
			&SceneChange => {
				// unwrap is save, see default_scene
				if scenes.last().unwrap().len() > 0 {
					scenes.push(default_scene.clone());
				}
			}
			&LocationChange(ref location) => {
				// unwraps are safe, see default_scene
				let mut current_scene = scenes.last_mut().unwrap();

				if current_scene.last().unwrap().parts.len() == 0 {
					current_scene.pop();
				}
                // TODO: Parse INT./EXT.
				current_scene.push(Location {name: location.clone(), ..Default::default()})
			}
            &ScenePart(ref scene_part) => {
                let scene_parts = &mut scenes.last_mut().unwrap().last_mut().unwrap().parts;
                scene_parts.push(scene_part.clone());
            }
			&Separator => {} //ignore
		}
	}

	scenes
}

#[allow(dead_code)]
fn condense_script_demo(properties: ScriptProperties, lines: &Vec<(LineAttributes, String)>) {
    let mut last_left_position = 0;
    let mut last_top_position = 0;

    for line in lines.iter() {
        let &(ref attributes, ref line) = line;

        if line.len() == 0 {
            continue;
        }

        // start new section
        if last_left_position != attributes.left ||
           attributes.top - last_top_position > 18 ||
           attributes.top - last_top_position < 0 {
            if ! (last_left_position == properties.speaker_direction_position ||
                  last_left_position == properties.speaker_position) {
                // empty line after last section
                println!("");
            }
        }

        match attributes.left {
            k if (k == properties.direction_position)
                => println!("{}", line),
            k if (k == properties.dialog_position)
                => println!("          {}", line),
            k if (k == properties.speaker_direction_position)
                => println!("               {}", line),
            k if (k == properties.speaker_position)
                => println!("                    {}", line),
            _   => println!("------- {}", line),
        }

        last_left_position = attributes.left;
        last_top_position = attributes.top;
    }
}

fn main() {
    let xml_file_name = env::args().skip(1).next().expect("No input file given");

    let file_reader = File::open(xml_file_name).expect("Could not open file");
    let buffered_file_reader = Box::new(BufReader::new(file_reader));

    let (properties, lines) = read_and_analyze_script(buffered_file_reader);

    //condense_script_demo(properties, &lines);
    println!("{:#?}", extract_scenes(&extract_script_parts(properties, &lines)));
}
<commit_msg>Implement extraction of location and location kind (ext,int,..)<commit_after>extern crate xml;
extern crate regex;

use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io::BufReader;

use xml::reader::{EventReader, XmlEvent};
use xml::attribute::OwnedAttribute;

#[derive(Debug, Clone, Default)]
struct LineAttributes {
    top: i32,
    left: i32,
    height: i32,
    page: u32,
}

fn read_attributes(attr_list: &Vec<OwnedAttribute>) -> LineAttributes {
    let mut attributes : LineAttributes = Default::default();

    for attr in attr_list {
        match attr.name.local_name.as_ref() {
            "top" => attributes.top = attr.value.parse().unwrap(),
            "left" => attributes.left = attr.value.parse().unwrap(),
            "height" => attributes.height = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    attributes
}

#[derive(Debug, Clone, Default)]
struct ScriptProperties {
    direction_position: i32,
    dialog_position: i32,
    speaker_direction_position: i32,
    speaker_position: i32,
    intra_paragraph_line_height: i32,
}

fn read_and_analyze_script(reader: Box<Read>) -> (ScriptProperties, Vec<(LineAttributes, String)>) {
    let mut script_properties: ScriptProperties = Default::default();
    let mut lines: Vec<(LineAttributes, String)> = Vec::new();

    // these maps are used to heuristically determine the ScriptProperties
    let mut position_uses: HashMap<i32, u32> = HashMap::new();
    let mut line_height_uses: HashMap<i32, u32> = HashMap::new();

    // states for the streaming xml parsing
    let mut current_line_attributes: LineAttributes = Default::default();
    let mut current_text_buffer = String::new();
    let mut current_page_number = 0;
    let mut last_line_height = 0;

    let parser = EventReader::new(reader);
    for event in parser {
        match event {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                match name.local_name.as_ref() {
                    "text" => {
                        current_line_attributes = read_attributes(&attributes);

                        current_text_buffer.clear();

                        // increase the count for the current left margin
                        *position_uses.entry(current_line_attributes.left)
                                      .or_insert(0) += 1;

                        // increase the count for the current top position diff
                        *line_height_uses.entry(current_line_attributes.top - last_line_height)
                                         .or_insert(0) += 1;
                        last_line_height = current_line_attributes.top;
                    }
                    "page" => {
                        last_line_height = 0;

                        for attr in attributes {
                            if "number" == attr.name.local_name {
                                current_page_number = attr.value.parse().unwrap();
                                break;
                            }
                        }
                    }
                    _ => {}
                }
            }
            Ok(XmlEvent::Characters(text)) => {
                if current_text_buffer.len() > 0 {
                    current_text_buffer.push(' ');
                }
                current_text_buffer.push_str(text.trim());
            }
            Ok(XmlEvent::EndElement { name, .. }) => {
                if name.local_name == "text" {
                    current_line_attributes.page = current_page_number;
                    lines.push((current_line_attributes.clone(), current_text_buffer.clone()));
                }
            }
            Ok(_) => {},
            Err(e) => panic!("Error parsing xml: {}", e),
        }
    }

    // the position_uses map should at least have 3 different entries
    if position_uses.len() < 3 {
        panic!("Script uses strange layout");
    }

    // copy the position uses map into a vector and sort by value desc
    let mut position_uses_vec = position_uses.into_iter().collect::<Vec<_>>();
    position_uses_vec.sort_by(|&a, &b| b.1.cmp(&a.1));

    // sort the top 3 entries by position again (right-exclusive range)
    position_uses_vec[0..3].sort_by(|&a, &b| b.0.cmp(&a.0));

    script_properties.speaker_position = position_uses_vec[0].0;
    script_properties.dialog_position = position_uses_vec[1].0;
    script_properties.direction_position = position_uses_vec[2].0;

    // take the next value between speaker and dialog as speaker_direction
    for &value in position_uses_vec.iter().skip(3) {
        let (position, _) = value;
        if position > script_properties.dialog_position &&
           position < script_properties.speaker_position {
            script_properties.speaker_direction_position = position;
            break;
        }
    }

    // use to most used line diff value to determine the specific sections
    let mut last_uses: u32 = 0;
    for (&line_height, &uses) in line_height_uses.iter() {
        if uses > last_uses {
            script_properties.intra_paragraph_line_height = line_height;
            last_uses = uses;
        }
    }

    (script_properties, lines)
}

#[derive(Debug, Clone)]
enum DialogPart {
    Dialog(String),
    Direction(String),
}

#[derive(Debug, Clone)]
enum ScenePart {
    Direction {
        direction: String,
        page: u32,
    },
    Dialog {
        speaker: String,
        dialog: Vec<DialogPart>,
        page: u32,
    }
}

#[derive(Debug, Clone)]
enum ScriptPart {
    Separator,
    ScenePart(ScenePart),
    LocationChange(String),
    SceneChange,
}

fn is_location_change(line: &str) -> bool {
    line.starts_with("INT.") || line.starts_with("EXT.")
}

fn is_scene_change(line: &str) -> bool {
    line.starts_with("CUT TO")
}

fn extract_script_parts(properties: ScriptProperties, lines: &Vec<(LineAttributes, String)>)
    -> Vec<ScriptPart> {
    let mut script_parts: Vec<ScriptPart> = Vec::new();
    let mut last_top_position = 0;

    for line in lines.iter() {
        let &(ref attributes, ref line) = line;

        if line.len() == 0 {
            continue;
        }

        // check if a new section starts
        if attributes.top - last_top_position > 18 ||
           attributes.top - last_top_position < 0 {
            // used to separate two consecutive script parts of the
            // same type. this is just a implementation detail of
            // the parsing. the Separator can be ignored later.
            script_parts.push(ScriptPart::Separator);
        }

        if attributes.left == properties.direction_position {
            if is_location_change(line) {
                script_parts.push(ScriptPart::LocationChange(line.clone()));
            } else {
                // ensure the last script part is a direction
                if let Some(&ScriptPart::ScenePart(ScenePart::Direction{..})) = script_parts.last() {
                } else {
                    script_parts.push(ScriptPart::ScenePart(
                        ScenePart::Direction{
                            direction: String::new(),
                            page: attributes.page,
                        }));
                }

                if let Some(&mut ScriptPart::ScenePart(ScenePart::Direction{ref mut direction, ..})) = script_parts.last_mut() {
                    if direction.len() > 0 {
                        direction.push(' ');
                    }
                    direction.push_str(line);
                }
            }
        } else if attributes.left == properties.speaker_position ||
                  attributes.left == properties.speaker_direction_position ||
                  attributes.left == properties.dialog_position {
            // Ensure the last script part is a dialog
            if let Some(&ScriptPart::ScenePart(ScenePart::Dialog{..})) = script_parts.last() {
            } else {
                script_parts.push(ScriptPart::ScenePart(
                    ScenePart::Dialog{
                        speaker: String::new(),
                        dialog: Vec::new(),
                        page: attributes.page,
                    }));
            }

            // get the dialog, should never fail (see above)
            if let Some(&mut ScriptPart::ScenePart(ScenePart::Dialog{ref mut speaker, ref mut dialog, ..})) = script_parts.last_mut() {
                if attributes.left == properties.speaker_position {
                    // there is only one speaker per dialog
                    speaker.push_str(line);
                } else if attributes.left == properties.speaker_direction_position {
                    if let Some(&DialogPart::Direction(_)) = dialog.last() {
                    } else {
                        dialog.push(DialogPart::Direction(String::new()));
                    }

                    if let Some(&mut DialogPart::Direction(ref mut direction)) = dialog.last_mut() {
                        if direction.len() > 0 {
                            direction.push(' ');
                        }
                        direction.push_str(line);
                    }
                } else if attributes.left == properties.dialog_position {
                    if let Some(&DialogPart::Dialog(_)) = dialog.last() {
                    } else {
                        dialog.push(DialogPart::Dialog(String::new()));
                    }

                    if let Some(&mut DialogPart::Dialog(ref mut dialog)) = dialog.last_mut() {
                        if dialog.len() > 0 {
                            dialog.push(' ');
                        }
                        dialog.push_str(line);
                    }
                }
            }
        } else {
            if is_scene_change(line) {
                script_parts.push(ScriptPart::SceneChange);
            }
        }

        last_top_position = attributes.top;
    }

    script_parts
}

#[derive(Clone, Debug)]
enum LocationType {
    Undefined,
    Internal,
    External,
    InternalExternal,
}

impl Default for LocationType {
    fn default() -> LocationType { LocationType::Undefined }
}

fn extract_location(name: &str) -> Location {
    let pattern = regex::Regex::new(r"(?:(?P<kind>INT\.|EXT\.|INT\./EXT\.)\s+)?(?P<location>.+)").unwrap();
    let mut location: Location = Default::default();

    if let Some(captures) = pattern.captures(name) {
        location.name = captures.name("location").unwrap().to_string();

        if let Some(location_kind) = captures.name("kind") {
            location.kind = match location_kind {
                "INT." => LocationType::Internal,
                "EXT." => LocationType::External,
                "INT./EXT." => LocationType::InternalExternal,
                _ => LocationType::Undefined,
            };
        }
    } else {
        location.name = name.to_string();
    }

    location
}

#[derive(Default, Clone, Debug)]
struct Location {
	kind: LocationType,
	name: String,
	parts: Vec<ScenePart>,
}

type Scene = Vec<Location>;

fn extract_scenes(script_parts: &Vec<ScriptPart>) -> Vec<Scene> {
	let mut scenes = Vec::new();

    // scene with default (empty) location
	let default_scene: Scene = vec![Default::default()];
	scenes.push(default_scene.clone());

	for script_part in script_parts.iter() {
		use ScriptPart::*;
		match script_part {
			&SceneChange => {
				// unwrap is save, see default_scene
				if scenes.last().unwrap().len() > 0 {
					scenes.push(default_scene.clone());
				}
			}
			&LocationChange(ref location) => {
				// unwraps are safe, see default_scene
				let mut current_scene = scenes.last_mut().unwrap();

				if current_scene.last().unwrap().parts.len() == 0 {
					current_scene.pop();
				}
                current_scene.push(extract_location(location));
			}
            &ScenePart(ref scene_part) => {
                let scene_parts = &mut scenes.last_mut().unwrap().last_mut().unwrap().parts;
                scene_parts.push(scene_part.clone());
            }
			&Separator => {} //ignore
		}
	}

	scenes
}

#[allow(dead_code)]
fn condense_script_demo(properties: ScriptProperties, lines: &Vec<(LineAttributes, String)>) {
    let mut last_left_position = 0;
    let mut last_top_position = 0;

    for line in lines.iter() {
        let &(ref attributes, ref line) = line;

        if line.len() == 0 {
            continue;
        }

        // start new section
        if last_left_position != attributes.left ||
           attributes.top - last_top_position > 18 ||
           attributes.top - last_top_position < 0 {
            if ! (last_left_position == properties.speaker_direction_position ||
                  last_left_position == properties.speaker_position) {
                // empty line after last section
                println!("");
            }
        }

        match attributes.left {
            k if (k == properties.direction_position)
                => println!("{}", line),
            k if (k == properties.dialog_position)
                => println!("          {}", line),
            k if (k == properties.speaker_direction_position)
                => println!("               {}", line),
            k if (k == properties.speaker_position)
                => println!("                    {}", line),
            _   => println!("------- {}", line),
        }

        last_left_position = attributes.left;
        last_top_position = attributes.top;
    }
}

fn main() {
    let xml_file_name = env::args().skip(1).next().expect("No input file given");

    let file_reader = File::open(xml_file_name).expect("Could not open file");
    let buffered_file_reader = Box::new(BufReader::new(file_reader));

    let (properties, lines) = read_and_analyze_script(buffered_file_reader);

    //condense_script_demo(properties, &lines);
    println!("{:#?}", extract_scenes(&extract_script_parts(properties, &lines)));
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::sync::mpsc::Sender;

use errors::*;
use messages::*;

/// Subscription
struct Subscription {
  /// Subscription
  subscriber: Sender<SerialResponse>,
  /// The ports it is subscribed to
  ports: Vec<String>,
}

impl Subscription {
  /// Send a message to a subscriber
  fn send_message(&self, msg: SerialResponse) -> Result<()> {
    self
      .subscriber
      .send(msg)
      .map_err(|e| ErrorKind::SendResponse(e).into())
  }

  // Register interest in a port
  fn add_port(&mut self, port_name: &String) {
    match self.ports.iter().position(|p| p == port_name) {
      None => self.ports.push(port_name.to_string()),
      Some(_) => debug!("Port already subscribed to"),
    }
  }

  // Remove interest in a port
  fn remove_port(&mut self, port_name: &String) {
    self.ports.retain(|p| *p != *port_name);
  }

  // Remove interest in a port
  fn remove_all_ports(&mut self) {
    self.ports.clear();
  }
}

/// The subscription manager maintains a registry of
/// subscriptions vs ports
/// and provides methods for sending
/// messages to subscribers
pub struct SubscriptionManager {
  /// The subscriptions
  subscriptions: HashMap<String, Subscription>,
}

impl SubscriptionManager {
  /// Create a new SubscriptionManager instance
  pub fn new() -> SubscriptionManager {
    SubscriptionManager { subscriptions: HashMap::new() }
  }

  /// Add a port to a subscription
  pub fn add_port(&mut self, sub_id: &String, port_name: &String) -> Result<()> {
    match self.subscriptions.get_mut(sub_id) {
      Some(sub) => {
        sub.add_port(port_name);
        Ok(())
      }
      None => Err(ErrorKind::SubscriptionNotFound(sub_id.to_string()).into()),
    }
  }

  /// Remove a single port from a given subscription or all subscriptions
  pub fn remove_port(&mut self, sub_id: &String, port_name: &String) -> Result<()> {
    match self.subscriptions.get_mut(sub_id) {
      Some(sub) => {
        sub.ports.retain(|p| p != port_name);
        Ok(())
      }
      None => Err(ErrorKind::SubscriptionNotFound(sub_id.to_string()).into()),
    }
  }

  /// Remove a port from all subscriptions
  pub fn remove_port_from_all(&mut self, port_name: &String) {
    for (_, sub) in self.subscriptions.iter_mut() {
      sub.ports.retain(|p| p != port_name);
    }
  }

  /// Remove all ports from a single subscription or all subscriptions
  pub fn clear_ports(&mut self, sub_id: Option<&String>) {
    match sub_id {
      Some(sid) => {
        match self.subscriptions.get_mut(sid) {
          Some(sub) => {
            sub.ports.clear();
          }
          None => {}
        }
      }
      None => {
        for (_, sub) in self.subscriptions.iter_mut() {
          sub.ports.clear();
        }
      }
    }
  }

  /// Add a subscription
  pub fn add_subscription(&mut self, sub: SubscriptionRequest) {
    self
      .subscriptions
      .entry(sub.sub_id)
      .or_insert(
        Subscription {
          subscriber: sub.subscriber,
          ports: Vec::new(),
        },
      );
  }

  /// Check if subscription exists, otherwise return error
  pub fn check_subscription_exists(&self, sub_id: &String) -> Result<()> {
    match self.subscriptions.contains_key(sub_id) {
      true => Ok(()),
      false => Err(ErrorKind::SubscriptionNotFound(sub_id.to_string()).into()),
    }
  }

  /// End a subscription
  pub fn end_subscription(&mut self, sub_id: &String) {
    self.subscriptions.remove(sub_id);
  }

  /// Send a message to the given subscription
  pub fn send_message(&self, sub_id: &String, msg: SerialResponse) -> Result<()> {
    match self.subscriptions.get(sub_id) {
      None => Err(ErrorKind::SubscriptionNotFound(sub_id.to_string()).into()),
      Some(sub) => {
        sub
          .subscriber
          .send(msg)
          .map_err(|e| ErrorKind::SendResponse(e).into())
      }
    }
  }

  /// Broadcast a messages to all subscribers, returning
  /// a vec of (sub_id,ErrorKind::SendResponse) failures if some sends fail
  pub fn broadcast_message(&self, msg: SerialResponse) -> Vec<Error> {
    debug!("Broadcasting '{}' to all subscribers", &msg);
    let mut res = Vec::new();
    for (sub_id, sub) in self.subscriptions.iter() {
      match self.send_message(sub_id, msg.clone()) {
        Err(e) => res.push(e),
        _ => debug!("  Broadcast to '{}' was successful", sub_id),
      }
    }
    res
  }

  /// Broadcast message to all subscribers registered for a given port
  pub fn broadcast_message_for_port(&self, port_name: &String, msg: SerialResponse) -> Vec<Error> {
    debug!(
      "Broadcasting '{}' to all subscribers registered on port {}",
      &msg,
      port_name
    );
    let mut res = Vec::new();
    for (sub_id, sub) in self.subscriptions.iter() {
      if sub
           .ports
           .iter()
           .position(|p| *p == *port_name)
           .is_some() {
        match self.send_message(sub_id, msg.clone()) {
          Err(e) => res.push(e),
          _ => debug!("  Broadcast to '{}' was successful", sub_id),
        }
      }
    }
    res
  }

  /// Get a list of ports that currently have subscriptions
  pub fn subscribed_ports(&mut self) -> HashSet<String> {
    let mut subscribed_ports = HashSet::<String>::new();
    for subs in self.subscriptions.values() {
      subscribed_ports.extend(subs.ports.clone());
    }
    subscribed_ports
  }
}
<commit_msg>Flesh out subscription manager tests more.<commit_after>use std::collections::{HashMap, HashSet};
use std::sync::mpsc::Sender;

use errors::*;
use messages::*;

/// Subscription
struct Subscription {
  /// Subscription
  subscriber: Sender<SerialResponse>,
  /// The ports it is subscribed to
  ports: Vec<String>,
}

impl Subscription {
  /// Send a message to a subscriber
  fn send_message(&self, msg: SerialResponse) -> Result<()> {
    self
      .subscriber
      .send(msg)
      .map_err(|e| ErrorKind::SendResponse(e).into())
  }

  // Register interest in a port
  fn add_port(&mut self, port_name: &String) {
    match self.ports.iter().position(|p| p == port_name) {
      None => self.ports.push(port_name.to_string()),
      Some(_) => debug!("Port already subscribed to"),
    }
  }

  // Remove interest in a port
  fn remove_port(&mut self, port_name: &String) {
    self.ports.retain(|p| *p != *port_name);
  }

  // Remove interest in a port
  fn remove_all_ports(&mut self) {
    self.ports.clear();
  }
}

/// The subscription manager maintains a registry of
/// subscriptions vs ports
/// and provides methods for sending
/// messages to subscribers
pub struct SubscriptionManager {
  /// The subscriptions
  subscriptions: HashMap<String, Subscription>,
}

impl SubscriptionManager {
  /// Create a new SubscriptionManager instance
  pub fn new() -> SubscriptionManager {
    SubscriptionManager { subscriptions: HashMap::new() }
  }

  /// Add a port to a subscription
  pub fn add_port(&mut self, sub_id: &String, port_name: &String) -> Result<()> {
    match self.subscriptions.get_mut(sub_id) {
      Some(sub) => {
        sub.add_port(port_name);
        Ok(())
      }
      None => Err(ErrorKind::SubscriptionNotFound(sub_id.to_string()).into()),
    }
  }

  /// Remove a single port from a given subscription or all subscriptions
  pub fn remove_port(&mut self, sub_id: &String, port_name: &String) -> Result<()> {
    match self.subscriptions.get_mut(sub_id) {
      Some(sub) => {
        sub.ports.retain(|p| p != port_name);
        Ok(())
      }
      None => Err(ErrorKind::SubscriptionNotFound(sub_id.to_string()).into()),
    }
  }

  /// Remove a port from all subscriptions
  pub fn remove_port_from_all(&mut self, port_name: &String) {
    for (_, sub) in self.subscriptions.iter_mut() {
      sub.ports.retain(|p| p != port_name);
    }
  }

  /// Remove all ports from a single subscription or all subscriptions
  pub fn clear_ports(&mut self, sub_id: Option<&String>) {
    match sub_id {
      Some(sid) => {
        match self.subscriptions.get_mut(sid) {
          Some(sub) => {
            sub.ports.clear();
          }
          None => {}
        }
      }
      None => {
        for (_, sub) in self.subscriptions.iter_mut() {
          sub.ports.clear();
        }
      }
    }
  }

  /// Add a subscription
  pub fn add_subscription(&mut self, sub: SubscriptionRequest) {
    self
      .subscriptions
      .entry(sub.sub_id)
      .or_insert(
        Subscription {
          subscriber: sub.subscriber,
          ports: Vec::new(),
        },
      );
  }

  /// Check if subscription exists, otherwise return error
  pub fn check_subscription_exists(&self, sub_id: &String) -> Result<()> {
    match self.subscriptions.contains_key(sub_id) {
      true => Ok(()),
      false => Err(ErrorKind::SubscriptionNotFound(sub_id.to_string()).into()),
    }
  }

  /// End a subscription
  pub fn end_subscription(&mut self, sub_id: &String) {
    self.subscriptions.remove(sub_id);
  }

  /// Send a message to the given subscription
  pub fn send_message(&self, sub_id: &String, msg: SerialResponse) -> Result<()> {
    match self.subscriptions.get(sub_id) {
      None => Err(ErrorKind::SubscriptionNotFound(sub_id.to_string()).into()),
      Some(sub) => {
        sub
          .subscriber
          .send(msg)
          .map_err(|e| ErrorKind::SendResponse(e).into())
      }
    }
  }

  /// Broadcast a messages to all subscribers, returning
  /// a vec of (sub_id,ErrorKind::SendResponse) failures if some sends fail
  pub fn broadcast_message(&self, msg: SerialResponse) -> Vec<Error> {
    debug!("Broadcasting '{}' to all subscribers", &msg);
    let mut res = Vec::new();
    for (sub_id, sub) in self.subscriptions.iter() {
      match self.send_message(sub_id, msg.clone()) {
        Err(e) => res.push(e),
        _ => debug!("  Broadcast to '{}' was successful", sub_id),
      }
    }
    res
  }

  /// Broadcast message to all subscribers registered for a given port
  pub fn broadcast_message_for_port(&self, port_name: &String, msg: SerialResponse) -> Vec<Error> {
    debug!(
      "Broadcasting '{}' to all subscribers registered on port {}",
      &msg,
      port_name
    );
    let mut res = Vec::new();
    for (sub_id, sub) in self.subscriptions.iter() {
      if sub
           .ports
           .iter()
           .position(|p| *p == *port_name)
           .is_some() {
        match self.send_message(sub_id, msg.clone()) {
          Err(e) => res.push(e),
          _ => debug!("  Broadcast to '{}' was successful", sub_id),
        }
      }
    }
    res
  }

  /// Get a list of ports that currently have subscriptions
  pub fn subscribed_ports(&mut self) -> HashSet<String> {
    let mut subscribed_ports = HashSet::<String>::new();
    for subs in self.subscriptions.values() {
      subscribed_ports.extend(subs.ports.clone());
    }
    subscribed_ports
  }
}

#[cfg(test)]
mod tests {

  use std::collections::HashSet;
  use std::iter::FromIterator;
  use std::sync::mpsc::{Receiver, Sender, channel};

  use super::*;
  use errors::*;
  use messages::*;

  #[test]
  fn test_subscriptions() {

    fn should_get_msg(
      rcvr: &Receiver<SerialResponse>,
      serial_resp: &SerialResponse,
      fail_tag: &str,
    ) {
      if let Ok(resp) = rcvr.try_recv() {
        assert_eq!(
          resp,
          serial_resp.clone(),
          "{} messages '{:?}' '{:?}' should be equal",
          fail_tag,
          resp,
          serial_resp.clone()
        )
      } else {
        panic!("{} should not have recieved anything", fail_tag);
      }
    }

    fn should_not_get_a_msg(rcvr: &Receiver<SerialResponse>, fail_tag: &str) {
      if let Ok(resp) = rcvr.try_recv() {
        panic!(
          "{} should not have recieved anything, got {:?}",
          fail_tag,
          resp
        );
      }
    }

    // manager
    let mut sub_manager = SubscriptionManager::new();
    // ports
    let ports = vec!["/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2"];
    let ports_set = HashSet::from_iter(ports.clone().into_iter().map(|p| p.to_string()));
    // subscriber1
    let sub1_id = "SUB1";
    let sub1_channel = channel::<SerialResponse>();
    let sub1_req = SubscriptionRequest {
      sub_id: sub1_id.to_string(),
      subscriber: sub1_channel.0,
    };
    // subscriber 2
    let sub2_id = "SUB2";
    let sub2_channel = channel::<SerialResponse>();
    let sub2_req = SubscriptionRequest {
      sub_id: sub2_id.to_string(),
      subscriber: sub2_channel.0,
    };
    // Add subscriber 1
    sub_manager.add_subscription(sub1_req);
    for port in ports.iter() {
      sub_manager
        .add_port(&sub1_id.to_string(), &port.to_string())
        .unwrap();
    }
    // Sub1 should be subscribed to all ports
    assert_eq!(
      sub_manager.subscribed_ports(),
      ports_set,
      "Port sets should be equal",
    );
    // Add subscriber2, but provide no ports
    sub_manager.add_subscription(sub2_req);
    // Broadcast a message to everyone
    let all_subscribers_msg = SerialResponse::Ok { msg: "Broadcast all!".to_string() };
    let mut all_res = sub_manager.broadcast_message(all_subscribers_msg.clone());
    assert!(all_res.len() == 0, "There should be no errors");
    should_get_msg(&sub1_channel.1, &all_subscribers_msg, "Subscriber 1");
    should_get_msg(&sub2_channel.1, &all_subscribers_msg, "Subscriber 2");
    // Send message to one subscriber
    let sub1_msg = SerialResponse::Ok { msg: "Only subscriber 1 should see this!".to_string() };
    sub_manager
      .send_message(&sub1_id.to_string(), sub1_msg.clone())
      .expect("Send to subscriber 1 should work!");
    should_get_msg(&sub1_channel.1, &sub1_msg, "Subscriber 1");
    should_not_get_a_msg(&sub2_channel.1, "Subscriber 2");
    // Send message to subscribers of a given port
    all_res = sub_manager.broadcast_message_for_port(&"/dev/ttyUSB2".to_string(), sub1_msg.clone());
    assert!(all_res.len() == 0, "There should be no errors");
    should_get_msg(&sub1_channel.1, &sub1_msg, "Subscriber 1");
    should_not_get_a_msg(&sub2_channel.1, "Subscriber 2");
    // unsubscribe sub1 from /dev/ttyUSB2
    sub_manager.remove_port(&sub1_id.to_string(), &"/dev/ttyUSB2".to_string()).expect("remvoving sub1 from port should not fail.");
    // No one should get message on ttyUSB2 now
    all_res = sub_manager.broadcast_message_for_port(&"/dev/ttyUSB2".to_string(), sub1_msg.clone());
    assert!(all_res.len() == 0, "There should be no errors");
    should_not_get_a_msg(&sub1_channel.1, "Subscriber 1");
    should_not_get_a_msg(&sub2_channel.1, "Subscriber 2");
  }

}<|endoftext|>


<commit_before>use std::{
    any::{Any, TypeId},
    collections::{BTreeMap, HashMap},
    marker::PhantomData,
    sync::{mpsc, Arc, Mutex},
};

use crate::shell::WindowRequest;

use dces::entity::Entity;

/// Internal wrapper that stores a message inside a box.
#[derive(Debug)]
pub struct MessageBox {
    message: Box<dyn Any + Send>,
    message_type: TypeId,
    target: Entity,
}

impl MessageBox {
    /// Creates a new `MessageBox`.
    pub fn new<M: Any + Send>(message: M, target: Entity) -> Self {
        MessageBox {
            message: Box::new(message),
            target,
            message_type: TypeId::of::<M>(),
        }
    }

    /// Check if the given type is the type of the message.
    pub fn is_type<M: Any>(&self) -> bool {
        self.message_type == TypeId::of::<M>()
    }

    /// Returns the type of the event.
    pub fn message_type(&self) -> TypeId {
        self.message_type
    }

    /// Downcasts the box to an concrete message.
    pub fn downcast<M: Any>(self) -> Result<M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(*self.message.downcast::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }

    /// Downcasts the box as reference of an concrete message.
    pub fn downcast_ref<M: Any>(&self) -> Result<&M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(&*self.message.downcast_ref::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }
}

/// The `MessageAdapter` provides a thread save entry point to sent
/// and read messages inside widget entities. They are processed inside the
/// method `message` defined in each widgets `State` code.
///
/// # Example
///
/// ```rust
/// // State
/// fn say_hello(entity: Entity, message_adapter: MessageAdapter) {
///     message_adapter.send_message(String::from("Hello rustician"), entity);
///     message_adapter.send_message(String::from("Did you recieve my message?"), entity);
/// }
///
/// impl MyState {}
///
/// // implementation for the State
/// impl State for MyState {
///     fn message(&mut self, mut messages: MessageReader, _registry: &mut Registry, _ctx: &mut Context) {
///         for message in messages.read::<String>() {
///             println!("{}", message);
///         }
///     }
/// }
/// ```
///
/// The example code snippet above will print two lines to stdout:
///
/// ```text
/// $ Hello rustician,
/// $  Did you receive my message?
/// ```
#[derive(Clone, Debug)]
pub struct MessageAdapter {
    messages: Arc<Mutex<BTreeMap<Entity, HashMap<TypeId, Vec<MessageBox>>>>>,
    window_sender: mpsc::Sender<WindowRequest>,
}

impl MessageAdapter {
    /// Creates a new message adapter
    pub fn new(window_sender: mpsc::Sender<WindowRequest>) -> Self {
        MessageAdapter {
            messages: Arc::new(Mutex::new(BTreeMap::new())),
            window_sender,
        }
    }

    /// Send a new message to the message pipeline.
    pub fn send_message<M: Any + Send>(&self, message: M, target: Entity) {
        // Docs say this method must be thread safe
        // to ensure thread safety,
        // do not release this lock until this method execution ends
        let mut locked_messages = self
            .messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.");
        locked_messages
            .entry(target)
            .or_insert_with(HashMap::new)
            .entry(TypeId::of::<M>())
            .or_insert_with(Vec::new)
            .push(MessageBox::new(message, target));

        self.window_sender
            .send(WindowRequest::Redraw)
            .expect("MessageAdapter::send_message: Cannot send redraw request.");
    }

    /// Returns a list of entities that has messages.
    pub(crate) fn entities(&self) -> Vec<Entity> {
        self.messages
            .lock()
            .expect("MessageAdapter::entities: Cannot lock messages.")
            .keys()
            .cloned()
            .collect()
    }

    /// Removes all messages for the given target entity. This is used
    /// to remove messages for entities that does not have a `State`
    /// to read the messages.
    pub(crate) fn remove_message_for_entity(&self, target: Entity) {
        self.messages
            .lock()
            .expect("MessageAdapter::remove_message_for_entity: Cannot lock messages.")
            .remove(&target);
    }

    /// Returns the number of messages in the queue.
    pub fn len(&self) -> usize {
        self.messages
            .lock()
            .expect("MessageAdapter::len: Cannot lock messages.")
            .len()
    }

    /// Returns `true` if the event message contains no events.
    pub fn is_empty(&self) -> bool {
        self.messages
            .lock()
            .expect("MessageAdapter::is_empty: Cannot lock messages.")
            .is_empty()
    }

    /// Returns a message reader for the given entity. Moves all
    /// messages for the entity from the adapter to the reader.
    pub(crate) fn message_reader(&self, entity: Entity) -> MessageReader {
        let messages = if let Some(messages) = self
            .messages
            .lock()
            .expect("MessageAdapter::message_reader: Cannot lock messages.")
            .remove(&entity)
        {
            messages
        } else {
            HashMap::new()
        };

        MessageReader::new(messages, entity)
    }
}

/// The `MessageReader` is used to access the messages of a widget.
pub struct MessageReader {
    messages: HashMap<TypeId, Vec<MessageBox>>,
    target: Entity,
}

impl MessageReader {
    /// Creates a new message reader.
    pub fn new(messages: HashMap<TypeId, Vec<MessageBox>>, target: Entity) -> Self {
        MessageReader { messages, target }
    }

    /// Returns the target entity of the reader.
    pub fn entity(&self) -> Entity {
        self.target
    }

    /// Returns `true` if the reader contains message for the specified type.
    pub fn contains_type<M: Any>(&self) -> bool {
        self.messages.contains_key(&TypeId::of::<M>())
    }

    /// Returns `true` if the reader contains no messages.
    pub fn is_empty(&self) -> bool {
        self.messages.is_empty()
    }

    /// Returns a message iterator for the given message type.
    pub fn read<M: Any + Send>(&mut self) -> MessageIterator<M> {
        let messages = if let Some(messages) = self.messages.remove(&TypeId::of::<M>()) {
            messages
        } else {
            vec![]
        };

        MessageIterator::new(messages)
    }
}

/// Iterator of messages.
#[derive(Debug)]
pub struct MessageIterator<M>
where
    M: Any + Send,
{
    messages: Vec<MessageBox>,
    _phantom: PhantomData<M>,
}

impl<M> MessageIterator<M>
where
    M: Any + Send,
{
    pub(crate) fn new(messages: Vec<MessageBox>) -> Self {
        MessageIterator {
            messages,
            _phantom: PhantomData::default(),
        }
    }
}

impl<M> Iterator for MessageIterator<M>
where
    M: Any + Send,
{
    type Item = M;

    fn next(&mut self) -> Option<Self::Item> {
        if self.messages.is_empty() {
            return None;
        }

        // unwrap is ok because only messages of the same type should
        // be stored in the vec
        Some(self.messages.remove(0).downcast::<M>().unwrap())
    }
}
<commit_msg>orbtk_core: typo correction in message_adapter<commit_after>use std::{
    any::{Any, TypeId},
    collections::{BTreeMap, HashMap},
    marker::PhantomData,
    sync::{mpsc, Arc, Mutex},
};

use crate::shell::WindowRequest;

use dces::entity::Entity;

/// Internal wrapper that stores a message inside a box.
#[derive(Debug)]
pub struct MessageBox {
    message: Box<dyn Any + Send>,
    message_type: TypeId,
    target: Entity,
}

impl MessageBox {
    /// Creates a new `MessageBox`.
    pub fn new<M: Any + Send>(message: M, target: Entity) -> Self {
        MessageBox {
            message: Box::new(message),
            target,
            message_type: TypeId::of::<M>(),
        }
    }

    /// Check if the given type is the type of the message.
    pub fn is_type<M: Any>(&self) -> bool {
        self.message_type == TypeId::of::<M>()
    }

    /// Returns the type of the event.
    pub fn message_type(&self) -> TypeId {
        self.message_type
    }

    /// Downcasts the box to a concrete message.
    pub fn downcast<M: Any>(self) -> Result<M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(*self.message.downcast::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }

    /// Downcasts the box as reference of a concrete message.
    pub fn downcast_ref<M: Any>(&self) -> Result<&M, String> {
        if self.message_type == TypeId::of::<M>() {
            return Ok(&*self.message.downcast_ref::<M>().unwrap());
        }

        Err("Wrong message type".to_string())
    }
}

/// The `MessageAdapter` provides a thread save entry point to sent
/// and read messages inside widget entities. They are processed inside the
/// method `message` defined in each widgets `State` code.
///
/// # Example
///
/// ```rust
/// // State
/// fn say_hello(entity: Entity, message_adapter: MessageAdapter) {
///     message_adapter.send_message(String::from("Hello rustician"), entity);
///     message_adapter.send_message(String::from("Did you recieve my message?"), entity);
/// }
///
/// impl MyState {}
///
/// // implementation for the State
/// impl State for MyState {
///     fn message(&mut self, mut messages: MessageReader, _registry: &mut Registry, _ctx: &mut Context) {
///         for message in messages.read::<String>() {
///             println!("{}", message);
///         }
///     }
/// }
/// ```
///
/// The example code snippet above will print two lines to stdout:
///
/// ```text
/// $ Hello rustician,
/// $  Did you receive my message?
/// ```
#[derive(Clone, Debug)]
pub struct MessageAdapter {
    messages: Arc<Mutex<BTreeMap<Entity, HashMap<TypeId, Vec<MessageBox>>>>>,
    window_sender: mpsc::Sender<WindowRequest>,
}

impl MessageAdapter {
    /// Creates a new message adapter
    pub fn new(window_sender: mpsc::Sender<WindowRequest>) -> Self {
        MessageAdapter {
            messages: Arc::new(Mutex::new(BTreeMap::new())),
            window_sender,
        }
    }

    /// Send a new message to the message pipeline.
    pub fn send_message<M: Any + Send>(&self, message: M, target: Entity) {
        // Docs say this method must be thread safe
        // to ensure thread safety,
        // do not release this lock until this method execution ends
        let mut locked_messages = self
            .messages
            .lock()
            .expect("MessageAdapter::send_message: Cannot lock messages.");
        locked_messages
            .entry(target)
            .or_insert_with(HashMap::new)
            .entry(TypeId::of::<M>())
            .or_insert_with(Vec::new)
            .push(MessageBox::new(message, target));

        self.window_sender
            .send(WindowRequest::Redraw)
            .expect("MessageAdapter::send_message: Cannot send redraw request.");
    }

    /// Returns a list of entities that has messages.
    pub(crate) fn entities(&self) -> Vec<Entity> {
        self.messages
            .lock()
            .expect("MessageAdapter::entities: Cannot lock messages.")
            .keys()
            .cloned()
            .collect()
    }

    /// Removes all messages for the given target entity. This is used
    /// to remove messages for entities that does not have a `State`
    /// to read the messages.
    pub(crate) fn remove_message_for_entity(&self, target: Entity) {
        self.messages
            .lock()
            .expect("MessageAdapter::remove_message_for_entity: Cannot lock messages.")
            .remove(&target);
    }

    /// Returns the number of messages in the queue.
    pub fn len(&self) -> usize {
        self.messages
            .lock()
            .expect("MessageAdapter::len: Cannot lock messages.")
            .len()
    }

    /// Returns `true` if the event message contains no events.
    pub fn is_empty(&self) -> bool {
        self.messages
            .lock()
            .expect("MessageAdapter::is_empty: Cannot lock messages.")
            .is_empty()
    }

    /// Returns a message reader for the given entity. Moves all
    /// messages for the entity from the adapter to the reader.
    pub(crate) fn message_reader(&self, entity: Entity) -> MessageReader {
        let messages = if let Some(messages) = self
            .messages
            .lock()
            .expect("MessageAdapter::message_reader: Cannot lock messages.")
            .remove(&entity)
        {
            messages
        } else {
            HashMap::new()
        };

        MessageReader::new(messages, entity)
    }
}

/// The `MessageReader` is used to access the messages of a widget.
pub struct MessageReader {
    messages: HashMap<TypeId, Vec<MessageBox>>,
    target: Entity,
}

impl MessageReader {
    /// Creates a new message reader.
    pub fn new(messages: HashMap<TypeId, Vec<MessageBox>>, target: Entity) -> Self {
        MessageReader { messages, target }
    }

    /// Returns the target entity of the reader.
    pub fn entity(&self) -> Entity {
        self.target
    }

    /// Returns `true` if the reader contains message for the specified type.
    pub fn contains_type<M: Any>(&self) -> bool {
        self.messages.contains_key(&TypeId::of::<M>())
    }

    /// Returns `true` if the reader contains no messages.
    pub fn is_empty(&self) -> bool {
        self.messages.is_empty()
    }

    /// Returns a message iterator for the given message type.
    pub fn read<M: Any + Send>(&mut self) -> MessageIterator<M> {
        let messages = if let Some(messages) = self.messages.remove(&TypeId::of::<M>()) {
            messages
        } else {
            vec![]
        };

        MessageIterator::new(messages)
    }
}

/// Iterator of messages.
#[derive(Debug)]
pub struct MessageIterator<M>
where
    M: Any + Send,
{
    messages: Vec<MessageBox>,
    _phantom: PhantomData<M>,
}

impl<M> MessageIterator<M>
where
    M: Any + Send,
{
    pub(crate) fn new(messages: Vec<MessageBox>) -> Self {
        MessageIterator {
            messages,
            _phantom: PhantomData::default(),
        }
    }
}

impl<M> Iterator for MessageIterator<M>
where
    M: Any + Send,
{
    type Item = M;

    fn next(&mut self) -> Option<Self::Item> {
        if self.messages.is_empty() {
            return None;
        }

        // unwrap is ok because only messages of the same type should
        // be stored in the vec
        Some(self.messages.remove(0).downcast::<M>().unwrap())
    }
}
<|endoftext|>