<commit_before>
use gfx;
use gfx::DeviceHelper;
use graphics::{ Context, BackEnd };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform vec4 color;

attribute vec2 pos;

void main() {
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
uniform vec4 color;

in vec2 pos;

void main() {
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform vec4 color;

void main() {
    gl_FragColor = color;
}
"
    GLSL_150: b"
#version 150 core
uniform vec4 color;

out vec4 o_Color;

void main() {
    o_Color = color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
uniform vec4 color;

attribute vec2 pos;
attribute vec2 uv;

varying vec2 v_UV;

void main() {
    v_UV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
uniform sampler2D s_texture;
uniform vec4 color;

in vec2 pos;
in vec2 uv;
out vec2 v_UV;
void main() {
    v_UV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
uniform vec4 color;

varying vec2 v_UV;

void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * color;
}
"
    GLSL_150: b"
#version 150 core
uniform sampler2D s_texture;
uniform vec4 color;

out vec4 o_Color;

in vec2 v_UV;

void main()
{
    o_Color = texture(s_texture, v_UV) * color;
}
"
};

static POS_COMPONENTS: uint = 2;
static UV_COMPONENTS: uint = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32, ..2] }

#[vertex_format]
struct ColorFormat { color: [f32, ..4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32, ..2] }

#[allow(unused_imports)]
#[shader_param(Batch, OwnedBatch)]
struct Params {
    color: [f32, ..4],
}

#[allow(unused_imports)]
#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    color: [f32, ..4],
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct G2D {
    buffer_pos: gfx::BufferHandle<f32>,
    buffer_uv: gfx::BufferHandle<f32>,
    batch: OwnedBatch,
    batch_uv: OwnedBatchUV,
}

impl G2D {
    /// Creates a new G2D object.
    pub fn new<D: gfx::Device<C>,
               C: gfx::CommandBuffer>(device: &mut D) -> G2D {
        let program = device.link_program(
                VERTEX_SHADER.clone(),
                FRAGMENT_SHADER.clone()
            ).unwrap();
        let program_uv = device.link_program(
                VERTEX_SHADER_UV.clone(),
                FRAGMENT_SHADER_UV.clone()
            ).unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::UsageDynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ).into_iter());

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.extend(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ).into_iter());

        let params = Params {
                color: [1.0, ..4],
            };
        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, params).unwrap();

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

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::TextureKind::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
                &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            color: [1.0, ..4],
            s_texture: (texture, Some(sampler))
        };
        let mut batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv).unwrap();

        // Disable culling.
        batch.state.primitive.method =
            gfx::state::RasterMethod::Fill(gfx::state::CullMode::Nothing);
        batch_uv.state.primitive.method =
            gfx::state::RasterMethod::Fill(gfx::state::CullMode::Nothing);

        G2D {
            buffer_pos: buffer_pos,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C: gfx::CommandBuffer>(
        &mut self,
        renderer: &mut gfx::Renderer<C>,
        frame: &gfx::Frame,
        f: |c: Context, g: &mut GraphicsBackEnd<C>|
    ) {
        let ref mut g = GraphicsBackEnd::new(
            renderer,
            frame,
            self
        );
        let c = Context::abs(
            frame.width as f64,
            frame.height as f64
        );
        g.enable_alpha_blend();
        f(c, g);
        g.disable_alpha_blend();
    }
}

/// Used for rendering 2D graphics.
pub struct GraphicsBackEnd<'a, C: 'a + gfx::CommandBuffer> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    g2d: &'a mut G2D,
}

impl<'a, C: gfx::CommandBuffer> GraphicsBackEnd<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               g2d: &'a mut G2D) -> GraphicsBackEnd<'a, C> {
        GraphicsBackEnd {
            renderer: renderer,
            frame: frame,
            g2d: g2d,
        }
    }

    /// Returns true if texture has alpha channel.
    pub fn has_texture_alpha(&self, texture: &Texture) -> bool {
        use gfx::tex::Components::RGBA;

        texture.handle.get_info().format.get_components() == Some(RGBA)
    }

    /// Enabled alpha blending.
    pub fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::InverseFlag::{Normal, Inverse};
        use gfx::state::Factor;
        use gfx::state::BlendValue::SourceAlpha;

        let blend = gfx::state::Blend {
            value: [1.0, 1.0, 1.0, 1.0],
            color: gfx::state::BlendChannel {
                    equation: gfx::state::Equation::Add,
                    source: Factor(Normal, SourceAlpha),
                    destination: Factor(Inverse, SourceAlpha)
                },
            alpha: Default::default()
        };

        self.g2d.batch.state.blend = Some(blend);
        self.g2d.batch_uv.state.blend = Some(blend);
    }

    /// Disables alpha blending.
    pub fn disable_alpha_blend(&mut self) {
        self.g2d.batch.state.blend = None;
        self.g2d.batch_uv.state.blend = None;
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for GraphicsBackEnd<'a, C> {
    fn clear(&mut self, color: [f32, ..4]) {
        let &GraphicsBackEnd {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: color,
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::COLOR,
                frame
            );
    }

    fn color(&mut self, color: [f32, ..4]) {
        self.g2d.batch.param.color = color;
        self.g2d.batch_uv.param.color = color;
    }

    fn tri_list(&mut self, vertices: &[f32]) {
        let &GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &G2D {
                ref mut buffer_pos,
                ref mut batch,
                ..
            },
        } = self;

        renderer.update_buffer_vec(*buffer_pos, vertices, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch.slice = gfx::Slice {
                prim_type: gfx::PrimitiveType::TriangleList,
                start: 0,
                end: n as u32,
                kind: gfx::SliceKind::Vertex
            };
        renderer.draw(batch, *frame);
    }

    fn enable_texture(&mut self, texture: &Texture) {
        let ParamsUV {
            s_texture: (ref mut s_texture, _), ..
        } = self.g2d.batch_uv.param;
        *s_texture = texture.handle;
    }

    fn disable_texture(&mut self) {}

    fn tri_list_uv(&mut self, vertices: &[f32], texture_coords: &[f32]) {
        let &GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &G2D {
                ref mut buffer_pos,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * UV_COMPONENTS,
            texture_coords.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch_uv.slice = gfx::Slice {
                prim_type: gfx::PrimitiveType::TriangleList,
                start: 0,
                end: n as u32,
                kind: gfx::SliceKind::Vertex
            };
        renderer.draw(batch_uv, *frame);
    }
}
<commit_msg>Upgraded to latest Rust<commit_after>
use gfx;
use gfx::DeviceHelper;
use graphics::{ Context, BackEnd };
use graphics::BACK_END_MAX_VERTEX_COUNT as BUFFER_SIZE;

use Texture;

static VERTEX_SHADER: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform vec4 color;

attribute vec2 pos;

void main() {
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
uniform vec4 color;

in vec2 pos;

void main() {
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform vec4 color;

void main() {
    gl_FragColor = color;
}
"
    GLSL_150: b"
#version 150 core
uniform vec4 color;

out vec4 o_Color;

void main() {
    o_Color = color;
}
"
};

static VERTEX_SHADER_UV: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
uniform vec4 color;

attribute vec2 pos;
attribute vec2 uv;

varying vec2 v_UV;

void main() {
    v_UV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
    GLSL_150: b"
#version 150 core
uniform sampler2D s_texture;
uniform vec4 color;

in vec2 pos;
in vec2 uv;
out vec2 v_UV;
void main() {
    v_UV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}
"
};

static FRAGMENT_SHADER_UV: gfx::ShaderSource<'static> = shaders!{
    GLSL_120: b"
#version 120
uniform sampler2D s_texture;
uniform vec4 color;

varying vec2 v_UV;

void main()
{
    gl_FragColor = texture2D(s_texture, v_UV) * color;
}
"
    GLSL_150: b"
#version 150 core
uniform sampler2D s_texture;
uniform vec4 color;

out vec4 o_Color;

in vec2 v_UV;

void main()
{
    o_Color = texture(s_texture, v_UV) * color;
}
"
};

static POS_COMPONENTS: uint = 2;
static UV_COMPONENTS: uint = 2;

// Boiler plate for automatic attribute construction.
// Needs to be improved on gfx-rs side.
// For some reason, using ``*_COMPONENT` triggers some macros errors.

#[vertex_format]
struct PositionFormat { pos: [f32, ..2] }

#[vertex_format]
struct ColorFormat { color: [f32, ..4] }

#[vertex_format]
struct TexCoordsFormat { uv: [f32, ..2] }

#[allow(unused_imports)]
#[shader_param(Batch, OwnedBatch)]
struct Params {
    color: [f32, ..4],
}

#[allow(unused_imports)]
#[shader_param(BatchUV, OwnedBatchUV)]
struct ParamsUV {
    color: [f32, ..4],
    s_texture: gfx::shade::TextureParam,
}

/// The graphics back-end.
pub struct G2D {
    buffer_pos: gfx::BufferHandle<f32>,
    buffer_uv: gfx::BufferHandle<f32>,
    batch: OwnedBatch,
    batch_uv: OwnedBatchUV,
}

impl G2D {
    /// Creates a new G2D object.
    pub fn new<D: gfx::Device<C>,
               C: gfx::CommandBuffer>(device: &mut D) -> G2D {
        let program = device.link_program(
                VERTEX_SHADER.clone(),
                FRAGMENT_SHADER.clone()
            ).unwrap();
        let program_uv = device.link_program(
                VERTEX_SHADER_UV.clone(),
                FRAGMENT_SHADER_UV.clone()
            ).unwrap();

        let buffer_pos = device.create_buffer(
            POS_COMPONENTS * BUFFER_SIZE,
            gfx::BufferUsage::Dynamic);
        let buffer_uv = device.create_buffer(
            UV_COMPONENTS * BUFFER_SIZE,
            gfx::BufferUsage::Dynamic);

        let mut mesh = gfx::Mesh::new(BUFFER_SIZE as u32);
        mesh.attributes.extend(gfx::VertexFormat::generate(
            None::<PositionFormat>,
            buffer_pos.raw()
        ).into_iter());

        // Reuse parameters from `mesh`.
        let mut mesh_uv = mesh.clone();
        mesh_uv.attributes.extend(gfx::VertexFormat::generate(
            None::<TexCoordsFormat>,
            buffer_uv.raw()
        ).into_iter());

        let params = Params {
                color: [1.0, ..4],
            };
        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, params).unwrap();

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

        // Create a dummy texture
        let texture_info = gfx::tex::TextureInfo {
            width: 1,
            height: 1,
            depth: 1,
            levels: 1,
            kind: gfx::tex::TextureKind::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
                &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
            .unwrap();
        let params_uv = ParamsUV {
            color: [1.0, ..4],
            s_texture: (texture, Some(sampler))
        };
        let mut batch_uv = gfx::batch::OwnedBatch::new(
            mesh_uv, program_uv, params_uv).unwrap();

        // Disable culling.
        batch.state.primitive.method =
            gfx::state::RasterMethod::Fill(gfx::state::CullMode::Nothing);
        batch_uv.state.primitive.method =
            gfx::state::RasterMethod::Fill(gfx::state::CullMode::Nothing);

        G2D {
            buffer_pos: buffer_pos,
            buffer_uv: buffer_uv,
            batch: batch,
            batch_uv: batch_uv,
        }
    }

    /// Renders graphics to a Gfx renderer.
    pub fn draw<C: gfx::CommandBuffer>(
        &mut self,
        renderer: &mut gfx::Renderer<C>,
        frame: &gfx::Frame,
        f: |c: Context, g: &mut GraphicsBackEnd<C>|
    ) {
        let ref mut g = GraphicsBackEnd::new(
            renderer,
            frame,
            self
        );
        let c = Context::abs(
            frame.width as f64,
            frame.height as f64
        );
        g.enable_alpha_blend();
        f(c, g);
        g.disable_alpha_blend();
    }
}

/// Used for rendering 2D graphics.
pub struct GraphicsBackEnd<'a, C: 'a + gfx::CommandBuffer> {
    renderer: &'a mut gfx::Renderer<C>,
    frame: &'a gfx::Frame,
    g2d: &'a mut G2D,
}

impl<'a, C: gfx::CommandBuffer> GraphicsBackEnd<'a, C> {
    /// Creates a new object for rendering 2D graphics.
    pub fn new(renderer: &'a mut gfx::Renderer<C>,
               frame: &'a gfx::Frame,
               g2d: &'a mut G2D) -> GraphicsBackEnd<'a, C> {
        GraphicsBackEnd {
            renderer: renderer,
            frame: frame,
            g2d: g2d,
        }
    }

    /// Returns true if texture has alpha channel.
    pub fn has_texture_alpha(&self, texture: &Texture) -> bool {
        use gfx::tex::Components::RGBA;

        texture.handle.get_info().format.get_components() == Some(RGBA)
    }

    /// Enabled alpha blending.
    pub fn enable_alpha_blend(&mut self) {
        use std::default::Default;
        use gfx::state::InverseFlag::{Normal, Inverse};
        use gfx::state::Factor;
        use gfx::state::BlendValue::SourceAlpha;

        let blend = gfx::state::Blend {
            value: [1.0, 1.0, 1.0, 1.0],
            color: gfx::state::BlendChannel {
                    equation: gfx::state::Equation::Add,
                    source: Factor(Normal, SourceAlpha),
                    destination: Factor(Inverse, SourceAlpha)
                },
            alpha: Default::default()
        };

        self.g2d.batch.state.blend = Some(blend);
        self.g2d.batch_uv.state.blend = Some(blend);
    }

    /// Disables alpha blending.
    pub fn disable_alpha_blend(&mut self) {
        self.g2d.batch.state.blend = None;
        self.g2d.batch_uv.state.blend = None;
    }
}

impl<'a, C: gfx::CommandBuffer> BackEnd<Texture>
for GraphicsBackEnd<'a, C> {
    fn clear(&mut self, color: [f32, ..4]) {
        let &GraphicsBackEnd {
            ref mut renderer,
            frame,
            ..
        } = self;
        renderer.clear(
                gfx::ClearData {
                    color: color,
                    depth: 0.0,
                    stencil: 0,
                },
                gfx::COLOR,
                frame
            );
    }

    fn color(&mut self, color: [f32, ..4]) {
        self.g2d.batch.param.color = color;
        self.g2d.batch_uv.param.color = color;
    }

    fn tri_list(&mut self, vertices: &[f32]) {
        let &GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &G2D {
                ref mut buffer_pos,
                ref mut batch,
                ..
            },
        } = self;

        renderer.update_buffer_vec(*buffer_pos, vertices, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch.slice = gfx::Slice {
                prim_type: gfx::PrimitiveType::TriangleList,
                start: 0,
                end: n as u32,
                kind: gfx::SliceKind::Vertex
            };
        renderer.draw(batch, *frame);
    }

    fn enable_texture(&mut self, texture: &Texture) {
        let ParamsUV {
            s_texture: (ref mut s_texture, _), ..
        } = self.g2d.batch_uv.param;
        *s_texture = texture.handle;
    }

    fn disable_texture(&mut self) {}

    fn tri_list_uv(&mut self, vertices: &[f32], texture_coords: &[f32]) {
        let &GraphicsBackEnd {
            ref mut renderer,
            ref frame,
            g2d: &G2D {
                ref mut buffer_pos,
                ref mut buffer_uv,
                ref mut batch_uv,
                ..
            },
        } = self;

        assert_eq!(
            vertices.len() * UV_COMPONENTS,
            texture_coords.len() * POS_COMPONENTS
        );
        renderer.update_buffer_vec(*buffer_pos, vertices, 0);
        renderer.update_buffer_vec(*buffer_uv, texture_coords, 0);

        let n = vertices.len() / POS_COMPONENTS;
        batch_uv.slice = gfx::Slice {
                prim_type: gfx::PrimitiveType::TriangleList,
                start: 0,
                end: n as u32,
                kind: gfx::SliceKind::Vertex
            };
        renderer.draw(batch_uv, *frame);
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "xray")]

extern crate rusoto_core;
extern crate rusoto_xray;

use rusoto_xray::{XRay, XRayClient, GetServiceGraphRequest};
use rusoto_core::{DefaultCredentialsProvider, Region};
use rusoto_core::default_tls_client;

// duplicates the AWS X-Ray CLI example, which gets an (empty) service graph
// for the last 600 seconds
#[test]
fn should_get_service_graph() {
    let credentials = DefaultCredentialsProvider::new().unwrap();
    let client = XRayClient::new(default_tls_client().unwrap(), credentials, Region::UsEast1);

    let time: f64 = 1503868350.0; // time at the writing of this test

    let request = GetServiceGraphRequest {
        start_time: time - 600.0,
        end_time: time,
        ..Default::default()
    };

    let result = client.get_service_graph(&request);
    println!("{:#?}", result);
    result.unwrap();
}
<commit_msg>Fix XRay integration test.<commit_after>#![cfg(feature = "xray")]

extern crate time;
extern crate rusoto_core;
extern crate rusoto_xray;

use time::get_time;
use rusoto_xray::{XRay, XRayClient, GetServiceGraphRequest};
use rusoto_core::{DefaultCredentialsProvider, Region};
use rusoto_core::default_tls_client;

// duplicates the AWS X-Ray CLI example, which gets an (empty) service graph
// for the last 600 seconds
#[test]
fn should_get_service_graph() {
    let credentials = DefaultCredentialsProvider::new().unwrap();
    let client = XRayClient::new(default_tls_client().unwrap(), credentials, Region::UsEast1);

    let time = (get_time().sec - 30) as f64; // 30 seconds in the past

    let request = GetServiceGraphRequest {
        start_time: time - 600.0,
        end_time: time,
        ..Default::default()
    };

    let result = client.get_service_graph(&request);
    println!("{:#?}", result);
    result.unwrap();
}
<|endoftext|>


<commit_before>use {Color, Rgb, Luma, Xyz, Lab, Lch, Hsv, ColorSpace, Mix, Shade, GetHue, Hue, Saturate, RgbHue, clamp};

///Linear HSL color space with an alpha component.
///
///The HSL color space can be seen as a cylindrical version of
///[RGB](struct.Rgb.html), where the `hue` is the angle around the color
///cylinder, the `saturation` is the distance from the center, and the
///`lightness` is the height from the bottom. Its composition makes it
///especially good for operations like changing green to red, making a color
///more gray, or making it darker.
///
///See [HSV](struct.Hsv.html) for a very similar color space, with brightness instead of lightness.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Hsl {
    ///The hue of the color, in degrees. Decides if it's red, blue, purple,
    ///etc.
	pub hue: RgbHue,

    ///The colorfulness of the color. 0.0 gives gray scale colors and 1.0 will
    ///give absolutely clear colors.
	pub saturation: f32,

    ///Decides how light the color will look. 0.0 will be black, 0.5 will give
    ///a clear color, and 1.0 will give white.
	pub lightness: f32,

    ///The transparency of the color. 0.0 is completely transparent and 1.0 is
    ///completely opaque.
	pub alpha: f32,
}

impl Hsl {
    ///Linear HSL.
	pub fn hsl(hue: RgbHue, saturation: f32, lightness: f32) -> Hsl {
		Hsl {
			hue: hue,
			saturation: saturation,
			lightness: lightness,
			alpha: 1.0,
		}
	}

	///Linear HSL and transparency.
	pub fn hsla(hue: RgbHue, saturation: f32, lightness: f32, alpha: f32) -> Hsl {
		Hsl {
			hue: hue,
			saturation: saturation,
			lightness: lightness,
			alpha: alpha,
		}
	}
}

impl ColorSpace for Hsl {
    fn is_valid(&self) -> bool {
        self.saturation >= 0.0 && self.saturation <= 1.0 &&
        self.lightness >= 0.0 && self.lightness <= 1.0 &&
        self.alpha >= 0.0 && self.alpha <= 1.0
    }

    fn clamp(&self) -> Hsl {
        let mut c = *self;
        c.clamp_self();
        c
    }

    fn clamp_self(&mut self) {
        self.saturation = clamp(self.saturation, 0.0, 1.0);
        self.lightness = clamp(self.lightness, 0.0, 1.0);
        self.alpha = clamp(self.alpha, 0.0, 1.0);
    }
}

impl Mix for Hsl {
	fn mix(&self, other: &Hsl, factor: f32) -> Hsl {
        let factor = clamp(factor, 0.0, 1.0);
        let hue_diff: f32 = (other.hue - self.hue).into();

        Hsl {
            hue: self.hue + factor * hue_diff,
            saturation: self.saturation + factor * (other.saturation - self.saturation),
            lightness: self.lightness + factor * (other.lightness - self.lightness),
            alpha: self.alpha + factor * (other.alpha - self.alpha),
        }
    }
}

impl Shade for Hsl {
    fn lighten(&self, amount: f32) -> Hsl {
        Hsl {
            hue: self.hue,
            saturation: self.saturation,
            lightness: self.lightness + amount,
            alpha: self.alpha,
        }
    }
}

impl GetHue for Hsl {
    type Hue = RgbHue;

    fn get_hue(&self) -> Option<RgbHue> {
        if self.saturation <= 0.0 {
            None
        } else {
            Some(self.hue)
        }
    }
}

impl Hue for Hsl {
    fn with_hue(&self, hue: RgbHue) -> Hsl {
        Hsl {
            hue: hue,
            saturation: self.saturation,
            lightness: self.lightness,
            alpha: self.alpha,
        }
    }

    fn shift_hue(&self, amount: RgbHue) -> Hsl {
        Hsl {
            hue: self.hue + amount,
            saturation: self.saturation,
            lightness: self.lightness,
            alpha: self.alpha,
        }
    }
}

impl Saturate for Hsl {
    fn saturate(&self, factor: f32) -> Hsl {
        Hsl {
            hue: self.hue,
            saturation: self.saturation * (1.0 + factor),
            lightness: self.lightness,
            alpha: self.alpha,
        }
    }
}

impl Default for Hsl {
	fn default() -> Hsl {
		Hsl::hsl(0.0.into(), 0.0, 0.0)
	}
}

from_color!(to Hsl from Rgb, Luma, Xyz, Lab, Lch, Hsv);

impl From<Rgb> for Hsl {
	fn from(rgb: Rgb) -> Hsl {
		enum Channel { Red, Green, Blue };

        let val_min = rgb.red.min(rgb.green).min(rgb.blue);
        let mut val_max = rgb.red;
        let mut chan_max = Channel::Red;

        if rgb.green > val_max {
            chan_max = Channel::Green;
            val_max = rgb.green;
        }

        if rgb.blue > val_max {
            chan_max = Channel::Blue;
            val_max = rgb.blue;
        }

        let diff = val_max - val_min;
        let lightness = (val_min + val_max) / 2.0;

        let hue = if diff == 0.0 {
            0.0
        } else {
            60.0 * match chan_max {
                Channel::Red => ((rgb.green - rgb.blue) / diff) % 6.0,
                Channel::Green => ((rgb.blue - rgb.red) / diff + 2.0),
                Channel::Blue => ((rgb.red - rgb.green) / diff + 4.0),
            }
        };

        let saturation = if diff == 0.0 {
            0.0
        } else {
            diff / (1.0 - (2.0 * lightness - 1.0).abs())
        };

        Hsl {
            hue: hue.into(),
            saturation: saturation,
            lightness: lightness,
            alpha: rgb.alpha,
        }
	}
}

impl From<Luma> for Hsl {
	fn from(luma: Luma) -> Hsl {
		Rgb::from(luma).into()
	}
}

impl From<Xyz> for Hsl {
	fn from(xyz: Xyz) -> Hsl {
		Rgb::from(xyz).into()
	}
}

impl From<Lab> for Hsl {
	fn from(lab: Lab) -> Hsl {
		Rgb::from(lab).into()
	}
}

impl From<Lch> for Hsl {
	fn from(lch: Lch) -> Hsl {
		Rgb::from(lch).into()
	}
}

impl From<Hsv> for Hsl {
    fn from(hsv: Hsv) -> Hsl {
    	let x = (2.0 - hsv.saturation) * hsv.value;
    	let saturation = if hsv.value == 0.0 {
    		0.0
    	} else if x < 1.0 {
    		hsv.saturation * hsv.value / x
    	} else {
    		hsv.saturation * hsv.value / (2.0 - x)
    	};

    	Hsl {
    		hue: hsv.hue,
    		saturation: saturation,
    		lightness: x / 2.0,
    		alpha: hsv.alpha,
    	}
    }
}

#[cfg(test)]
mod test {
    use super::Hsl;
    use ::{Rgb, Hsv};

    #[test]
    fn red() {
        let a = Hsl::from(Rgb::linear_rgb(1.0, 0.0, 0.0));
        let b = Hsl::hsl(0.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(0.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }

    #[test]
    fn orange() {
        let a = Hsl::from(Rgb::linear_rgb(1.0, 0.5, 0.0));
        let b = Hsl::hsl(30.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(30.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }

    #[test]
    fn green() {
        let a = Hsl::from(Rgb::linear_rgb(0.0, 1.0, 0.0));
        let b = Hsl::hsl(120.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(120.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }

    #[test]
    fn blue() {
        let a = Hsl::from(Rgb::linear_rgb(0.0, 0.0, 1.0));
        let b = Hsl::hsl(240.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(240.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }

    #[test]
    fn purple() {
        let a = Hsl::from(Rgb::linear_rgb(0.5, 0.0, 1.0));
        let b = Hsl::hsl(270.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(270.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }
}
<commit_msg>Implement Add and Sub for Hsl<commit_after>use std::ops::{Add, Sub};

use {Color, Rgb, Luma, Xyz, Lab, Lch, Hsv, ColorSpace, Mix, Shade, GetHue, Hue, Saturate, RgbHue, clamp};

///Linear HSL color space with an alpha component.
///
///The HSL color space can be seen as a cylindrical version of
///[RGB](struct.Rgb.html), where the `hue` is the angle around the color
///cylinder, the `saturation` is the distance from the center, and the
///`lightness` is the height from the bottom. Its composition makes it
///especially good for operations like changing green to red, making a color
///more gray, or making it darker.
///
///See [HSV](struct.Hsv.html) for a very similar color space, with brightness instead of lightness.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Hsl {
    ///The hue of the color, in degrees. Decides if it's red, blue, purple,
    ///etc.
	pub hue: RgbHue,

    ///The colorfulness of the color. 0.0 gives gray scale colors and 1.0 will
    ///give absolutely clear colors.
	pub saturation: f32,

    ///Decides how light the color will look. 0.0 will be black, 0.5 will give
    ///a clear color, and 1.0 will give white.
	pub lightness: f32,

    ///The transparency of the color. 0.0 is completely transparent and 1.0 is
    ///completely opaque.
	pub alpha: f32,
}

impl Hsl {
    ///Linear HSL.
	pub fn hsl(hue: RgbHue, saturation: f32, lightness: f32) -> Hsl {
		Hsl {
			hue: hue,
			saturation: saturation,
			lightness: lightness,
			alpha: 1.0,
		}
	}

	///Linear HSL and transparency.
	pub fn hsla(hue: RgbHue, saturation: f32, lightness: f32, alpha: f32) -> Hsl {
		Hsl {
			hue: hue,
			saturation: saturation,
			lightness: lightness,
			alpha: alpha,
		}
	}
}

impl ColorSpace for Hsl {
    fn is_valid(&self) -> bool {
        self.saturation >= 0.0 && self.saturation <= 1.0 &&
        self.lightness >= 0.0 && self.lightness <= 1.0 &&
        self.alpha >= 0.0 && self.alpha <= 1.0
    }

    fn clamp(&self) -> Hsl {
        let mut c = *self;
        c.clamp_self();
        c
    }

    fn clamp_self(&mut self) {
        self.saturation = clamp(self.saturation, 0.0, 1.0);
        self.lightness = clamp(self.lightness, 0.0, 1.0);
        self.alpha = clamp(self.alpha, 0.0, 1.0);
    }
}

impl Mix for Hsl {
	fn mix(&self, other: &Hsl, factor: f32) -> Hsl {
        let factor = clamp(factor, 0.0, 1.0);
        let hue_diff: f32 = (other.hue - self.hue).into();

        Hsl {
            hue: self.hue + factor * hue_diff,
            saturation: self.saturation + factor * (other.saturation - self.saturation),
            lightness: self.lightness + factor * (other.lightness - self.lightness),
            alpha: self.alpha + factor * (other.alpha - self.alpha),
        }
    }
}

impl Shade for Hsl {
    fn lighten(&self, amount: f32) -> Hsl {
        Hsl {
            hue: self.hue,
            saturation: self.saturation,
            lightness: self.lightness + amount,
            alpha: self.alpha,
        }
    }
}

impl GetHue for Hsl {
    type Hue = RgbHue;

    fn get_hue(&self) -> Option<RgbHue> {
        if self.saturation <= 0.0 {
            None
        } else {
            Some(self.hue)
        }
    }
}

impl Hue for Hsl {
    fn with_hue(&self, hue: RgbHue) -> Hsl {
        Hsl {
            hue: hue,
            saturation: self.saturation,
            lightness: self.lightness,
            alpha: self.alpha,
        }
    }

    fn shift_hue(&self, amount: RgbHue) -> Hsl {
        Hsl {
            hue: self.hue + amount,
            saturation: self.saturation,
            lightness: self.lightness,
            alpha: self.alpha,
        }
    }
}

impl Saturate for Hsl {
    fn saturate(&self, factor: f32) -> Hsl {
        Hsl {
            hue: self.hue,
            saturation: self.saturation * (1.0 + factor),
            lightness: self.lightness,
            alpha: self.alpha,
        }
    }
}

impl Default for Hsl {
	fn default() -> Hsl {
		Hsl::hsl(0.0.into(), 0.0, 0.0)
	}
}

impl Add<Hsl> for Hsl {
    type Output = Hsl;

    fn add(self, other: Hsl) -> Hsl {
        Hsl {
            hue: self.hue + other.hue,
            saturation: self.saturation + other.saturation,
            lightness: self.lightness + other.lightness,
            alpha: self.alpha + other.alpha,
        }
    }
}

impl Add<f32> for Hsl {
    type Output = Hsl;

    fn add(self, c: f32) -> Hsl {
        Hsl {
            hue: self.hue + c,
            saturation: self.saturation + c,
            lightness: self.lightness + c,
            alpha: self.alpha + c,
        }
    }
}

impl Sub<Hsl> for Hsl {
    type Output = Hsl;

    fn sub(self, other: Hsl) -> Hsl {
        Hsl {
            hue: self.hue - other.hue,
            saturation: self.saturation - other.saturation,
            lightness: self.lightness - other.lightness,
            alpha: self.alpha - other.alpha,
        }
    }
}

impl Sub<f32> for Hsl {
    type Output = Hsl;

    fn sub(self, c: f32) -> Hsl {
        Hsl {
            hue: self.hue - c,
            saturation: self.saturation - c,
            lightness: self.lightness - c,
            alpha: self.alpha - c,
        }
    }
}

from_color!(to Hsl from Rgb, Luma, Xyz, Lab, Lch, Hsv);

impl From<Rgb> for Hsl {
	fn from(rgb: Rgb) -> Hsl {
		enum Channel { Red, Green, Blue };

        let val_min = rgb.red.min(rgb.green).min(rgb.blue);
        let mut val_max = rgb.red;
        let mut chan_max = Channel::Red;

        if rgb.green > val_max {
            chan_max = Channel::Green;
            val_max = rgb.green;
        }

        if rgb.blue > val_max {
            chan_max = Channel::Blue;
            val_max = rgb.blue;
        }

        let diff = val_max - val_min;
        let lightness = (val_min + val_max) / 2.0;

        let hue = if diff == 0.0 {
            0.0
        } else {
            60.0 * match chan_max {
                Channel::Red => ((rgb.green - rgb.blue) / diff) % 6.0,
                Channel::Green => ((rgb.blue - rgb.red) / diff + 2.0),
                Channel::Blue => ((rgb.red - rgb.green) / diff + 4.0),
            }
        };

        let saturation = if diff == 0.0 {
            0.0
        } else {
            diff / (1.0 - (2.0 * lightness - 1.0).abs())
        };

        Hsl {
            hue: hue.into(),
            saturation: saturation,
            lightness: lightness,
            alpha: rgb.alpha,
        }
	}
}

impl From<Luma> for Hsl {
	fn from(luma: Luma) -> Hsl {
		Rgb::from(luma).into()
	}
}

impl From<Xyz> for Hsl {
	fn from(xyz: Xyz) -> Hsl {
		Rgb::from(xyz).into()
	}
}

impl From<Lab> for Hsl {
	fn from(lab: Lab) -> Hsl {
		Rgb::from(lab).into()
	}
}

impl From<Lch> for Hsl {
	fn from(lch: Lch) -> Hsl {
		Rgb::from(lch).into()
	}
}

impl From<Hsv> for Hsl {
    fn from(hsv: Hsv) -> Hsl {
    	let x = (2.0 - hsv.saturation) * hsv.value;
    	let saturation = if hsv.value == 0.0 {
    		0.0
    	} else if x < 1.0 {
    		hsv.saturation * hsv.value / x
    	} else {
    		hsv.saturation * hsv.value / (2.0 - x)
    	};

    	Hsl {
    		hue: hsv.hue,
    		saturation: saturation,
    		lightness: x / 2.0,
    		alpha: hsv.alpha,
    	}
    }
}

#[cfg(test)]
mod test {
    use super::Hsl;
    use ::{Rgb, Hsv};

    #[test]
    fn red() {
        let a = Hsl::from(Rgb::linear_rgb(1.0, 0.0, 0.0));
        let b = Hsl::hsl(0.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(0.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }

    #[test]
    fn orange() {
        let a = Hsl::from(Rgb::linear_rgb(1.0, 0.5, 0.0));
        let b = Hsl::hsl(30.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(30.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }

    #[test]
    fn green() {
        let a = Hsl::from(Rgb::linear_rgb(0.0, 1.0, 0.0));
        let b = Hsl::hsl(120.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(120.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }

    #[test]
    fn blue() {
        let a = Hsl::from(Rgb::linear_rgb(0.0, 0.0, 1.0));
        let b = Hsl::hsl(240.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(240.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }

    #[test]
    fn purple() {
        let a = Hsl::from(Rgb::linear_rgb(0.5, 0.0, 1.0));
        let b = Hsl::hsl(270.0.into(), 1.0, 0.5);
        let c = Hsl::from(Hsv::hsv(270.0.into(), 1.0, 1.0));

        assert_approx_eq!(a, b, [hue, saturation, lightness]);
        assert_approx_eq!(a, c, [hue, saturation, lightness]);
    }
}
<|endoftext|>


<commit_before>use audio::{AudioData, Operation as AudioOperation};
use color::{self, Color};
use light::{ShadowMap, ShadowProjection};
use material::{self, Material};
use mesh::DynamicMesh;
use node::{Node, NodePointer};
use object::Object;
use render::GpuData;
use text::{Operation as TextOperation, TextData};

use cgmath::Transform;
use froggy;
use mint;

use std::sync::{Arc, Mutex};
use std::sync::{atomic, mpsc};

/// Assigns unique IDs to spawned scene nodes.
///
/// Must be incremented in each call to `spawn_scene` (use `fetch_add` or otherwise).
static SCENE_UID_COUNTER: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

#[derive(Clone, Debug)]
pub(crate) enum SubLight {
    Ambient,
    Directional,
    Hemisphere { ground: Color },
    Point,
}

#[derive(Clone, Debug)]
pub(crate) struct LightData {
    pub(crate) color: Color,
    pub(crate) intensity: f32,
    pub(crate) sub_light: SubLight,
    pub(crate) shadow: Option<(ShadowMap, ShadowProjection)>,
}

/// A sub-node specifies and contains the context-specific data owned by a `Node`.
#[derive(Debug)]
pub(crate) enum SubNode {
    /// No extra data, such as in the case of `Group`.
    Empty,
    /// Audio data.
    Audio(AudioData),
    /// Renderable text for 2D user interface.
    UiText(TextData),
    /// Renderable 3D content, such as a mesh.
    Visual(Material, GpuData),
    /// Lighting information for illumination and shadow casting.
    Light(LightData),
    /// Marks the root object of a `Scene`.
    Scene,
}

pub(crate) type Message = (froggy::WeakPointer<Node>, Operation);
pub(crate) enum Operation {
    SetAudio(AudioOperation),
    SetParent(NodePointer),
    SetVisible(bool),
    SetText(TextOperation),
    SetTransform(
        Option<mint::Point3<f32>>,
        Option<mint::Quaternion<f32>>,
        Option<f32>,
    ),
    SetMaterial(Material),
    SetTexelRange(mint::Point2<i16>, mint::Vector2<u16>),
    SetShadow(ShadowMap, ShadowProjection),
}

pub(crate) type HubPtr = Arc<Mutex<Hub>>;

pub(crate) struct Hub {
    pub(crate) nodes: froggy::Storage<Node>,
    pub(crate) message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl Hub {
    pub(crate) fn new() -> HubPtr {
        let (tx, rx) = mpsc::channel();
        let hub = Hub {
            nodes: froggy::Storage::new(),
            message_tx: tx,
            message_rx: rx,
        };
        Arc::new(Mutex::new(hub))
    }

    fn spawn(
        &mut self,
        sub: SubNode,
    ) -> Object {
        Object {
            node: self.nodes.create(sub.into()),
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn spawn_empty(&mut self) -> Object {
        self.spawn(SubNode::Empty)
    }

    pub(crate) fn spawn_visual(
        &mut self,
        mat: Material,
        gpu_data: GpuData,
    ) -> Object {
        self.spawn(SubNode::Visual(mat, gpu_data))
    }

    pub(crate) fn spawn_light(
        &mut self,
        data: LightData,
    ) -> Object {
        self.spawn(SubNode::Light(data))
    }

    pub(crate) fn spawn_ui_text(
        &mut self,
        text: TextData,
    ) -> Object {
        self.spawn(SubNode::UiText(text))
    }

    pub(crate) fn spawn_audio_source(
        &mut self,
        data: AudioData,
    ) -> Object {
        self.spawn(SubNode::Audio(data))
    }

    pub(crate) fn spawn_scene(&mut self) -> Object {
        let uid = SCENE_UID_COUNTER.fetch_add(1, atomic::Ordering::Relaxed);
        let tx = self.message_tx.clone();
        let node = self.nodes.create(Node {
            scene_id: Some(uid),
            .. SubNode::Scene.into()
        });
        Object { node, tx }
    }

    pub(crate) fn process_messages(&mut self) {
        while let Ok((pnode, operation)) = self.message_rx.try_recv() {
            let node = match pnode.upgrade() {
                Ok(ptr) => &mut self.nodes[&ptr],
                Err(_) => continue,
            };
            match operation {
                Operation::SetAudio(operation) => if let SubNode::Audio(ref mut data) = node.sub_node {
                    Hub::process_audio(operation, data);
                },
                Operation::SetParent(parent) => {
                    node.parent = Some(parent);
                }
                Operation::SetVisible(visible) => {
                    node.visible = visible;
                }
                Operation::SetTransform(pos, rot, scale) => {
                    if let Some(pos) = pos {
                        node.transform.disp = mint::Vector3::from(pos).into();
                    }
                    if let Some(rot) = rot {
                        node.transform.rot = rot.into();
                    }
                    if let Some(scale) = scale {
                        node.transform.scale = scale;
                    }
                }
                Operation::SetMaterial(material) => if let SubNode::Visual(ref mut mat, _) = node.sub_node {
                    *mat = material;
                },
                Operation::SetTexelRange(base, size) => if let SubNode::Visual(ref mut material, _) = node.sub_node {
                    match *material {
                        material::Material::Sprite(ref mut params) => params.map.set_texel_range(base, size),
                        _ => panic!("Unsupported material for texel range request"),
                    }
                },
                Operation::SetText(operation) => if let SubNode::UiText(ref mut data) = node.sub_node {
                    Hub::process_text(operation, data);
                },
                Operation::SetShadow(map, proj) => if let SubNode::Light(ref mut data) = node.sub_node {
                    data.shadow = Some((map, proj));
                },
            }
        }
        self.nodes.sync_pending();
    }

    fn process_audio(
        operation: AudioOperation,
        data: &mut AudioData,
    ) {
        match operation {
            AudioOperation::Append(clip) => data.source.append(clip),
            AudioOperation::Pause => data.source.pause(),
            AudioOperation::Resume => data.source.resume(),
            AudioOperation::Stop => data.source.stop(),
            AudioOperation::SetVolume(volume) => data.source.set_volume(volume),
        }
    }

    fn process_text(
        operation: TextOperation,
        data: &mut TextData,
    ) {
        use gfx_glyph::Scale;
        match operation {
            TextOperation::Color(color) => {
                let rgb = color::to_linear_rgb(color);
                data.section.color = [rgb[0], rgb[1], rgb[2], 0.0];
            }
            TextOperation::Font(font) => data.font = font,
            TextOperation::Layout(layout) => data.layout = layout,
            TextOperation::Opacity(opacity) => data.section.color[3] = opacity,
            TextOperation::Pos(point) => data.section.screen_position = (point.x, point.y),
            // TODO: somehow grab window::hdpi_factor and multiply size
            TextOperation::Scale(scale) => data.section.scale = Scale::uniform(scale),
            TextOperation::Size(size) => data.section.bounds = (size.x, size.y),
            TextOperation::Text(text) => data.section.text = text,
        }
    }

    pub(crate) fn update_graph(&mut self) {
        let mut cursor = self.nodes.cursor();
        while let Some((left, mut item, _)) = cursor.next() {
            if !item.visible {
                item.world_visible = false;
                continue;
            }
            let (visibility, affilation, transform) = match item.parent {
                Some(ref parent_ptr) => match left.get(parent_ptr) {
                    Some(parent) => (
                        parent.world_visible,
                        parent.scene_id,
                        parent.world_transform.concat(&item.transform),
                    ),
                    None => {
                        error!("Parent node was created after the child, ignoring");
                        (false, item.scene_id, item.transform)
                    }
                },
                None => (true, item.scene_id, item.transform),
            };
            item.world_visible = visibility;
            item.scene_id = affilation;
            item.world_transform = transform;
        }
    }

    pub(crate) fn update_mesh(
        &mut self,
        mesh: &DynamicMesh,
    ) {
        match self.nodes[&mesh.node].sub_node {
            SubNode::Visual(_, ref mut gpu_data) => gpu_data.pending = Some(mesh.dynamic.clone()),
            _ => unreachable!(),
        }
    }
}
<commit_msg>Decrease scope of hub::SCENE_UID_COUNTER<commit_after>use audio::{AudioData, Operation as AudioOperation};
use color::{self, Color};
use light::{ShadowMap, ShadowProjection};
use material::{self, Material};
use mesh::DynamicMesh;
use node::{Node, NodePointer};
use object::Object;
use render::GpuData;
use text::{Operation as TextOperation, TextData};

use cgmath::Transform;
use froggy;
use mint;

use std::sync::{Arc, Mutex};
use std::sync::{atomic, mpsc};

#[derive(Clone, Debug)]
pub(crate) enum SubLight {
    Ambient,
    Directional,
    Hemisphere { ground: Color },
    Point,
}

#[derive(Clone, Debug)]
pub(crate) struct LightData {
    pub(crate) color: Color,
    pub(crate) intensity: f32,
    pub(crate) sub_light: SubLight,
    pub(crate) shadow: Option<(ShadowMap, ShadowProjection)>,
}

/// A sub-node specifies and contains the context-specific data owned by a `Node`.
#[derive(Debug)]
pub(crate) enum SubNode {
    /// No extra data, such as in the case of `Group`.
    Empty,
    /// Audio data.
    Audio(AudioData),
    /// Renderable text for 2D user interface.
    UiText(TextData),
    /// Renderable 3D content, such as a mesh.
    Visual(Material, GpuData),
    /// Lighting information for illumination and shadow casting.
    Light(LightData),
    /// Marks the root object of a `Scene`.
    Scene,
}

pub(crate) type Message = (froggy::WeakPointer<Node>, Operation);
pub(crate) enum Operation {
    SetAudio(AudioOperation),
    SetParent(NodePointer),
    SetVisible(bool),
    SetText(TextOperation),
    SetTransform(
        Option<mint::Point3<f32>>,
        Option<mint::Quaternion<f32>>,
        Option<f32>,
    ),
    SetMaterial(Material),
    SetTexelRange(mint::Point2<i16>, mint::Vector2<u16>),
    SetShadow(ShadowMap, ShadowProjection),
}

pub(crate) type HubPtr = Arc<Mutex<Hub>>;

pub(crate) struct Hub {
    pub(crate) nodes: froggy::Storage<Node>,
    pub(crate) message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl Hub {
    pub(crate) fn new() -> HubPtr {
        let (tx, rx) = mpsc::channel();
        let hub = Hub {
            nodes: froggy::Storage::new(),
            message_tx: tx,
            message_rx: rx,
        };
        Arc::new(Mutex::new(hub))
    }

    fn spawn(
        &mut self,
        sub: SubNode,
    ) -> Object {
        Object {
            node: self.nodes.create(sub.into()),
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn spawn_empty(&mut self) -> Object {
        self.spawn(SubNode::Empty)
    }

    pub(crate) fn spawn_visual(
        &mut self,
        mat: Material,
        gpu_data: GpuData,
    ) -> Object {
        self.spawn(SubNode::Visual(mat, gpu_data))
    }

    pub(crate) fn spawn_light(
        &mut self,
        data: LightData,
    ) -> Object {
        self.spawn(SubNode::Light(data))
    }

    pub(crate) fn spawn_ui_text(
        &mut self,
        text: TextData,
    ) -> Object {
        self.spawn(SubNode::UiText(text))
    }

    pub(crate) fn spawn_audio_source(
        &mut self,
        data: AudioData,
    ) -> Object {
        self.spawn(SubNode::Audio(data))
    }

    pub(crate) fn spawn_scene(&mut self) -> Object {
        static SCENE_UID_COUNTER: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
        let uid = SCENE_UID_COUNTER.fetch_add(1, atomic::Ordering::Relaxed);
        let tx = self.message_tx.clone();
        let node = self.nodes.create(Node {
            scene_id: Some(uid),
            .. SubNode::Scene.into()
        });
        Object { node, tx }
    }

    pub(crate) fn process_messages(&mut self) {
        while let Ok((pnode, operation)) = self.message_rx.try_recv() {
            let node = match pnode.upgrade() {
                Ok(ptr) => &mut self.nodes[&ptr],
                Err(_) => continue,
            };
            match operation {
                Operation::SetAudio(operation) => if let SubNode::Audio(ref mut data) = node.sub_node {
                    Hub::process_audio(operation, data);
                },
                Operation::SetParent(parent) => {
                    node.parent = Some(parent);
                }
                Operation::SetVisible(visible) => {
                    node.visible = visible;
                }
                Operation::SetTransform(pos, rot, scale) => {
                    if let Some(pos) = pos {
                        node.transform.disp = mint::Vector3::from(pos).into();
                    }
                    if let Some(rot) = rot {
                        node.transform.rot = rot.into();
                    }
                    if let Some(scale) = scale {
                        node.transform.scale = scale;
                    }
                }
                Operation::SetMaterial(material) => if let SubNode::Visual(ref mut mat, _) = node.sub_node {
                    *mat = material;
                },
                Operation::SetTexelRange(base, size) => if let SubNode::Visual(ref mut material, _) = node.sub_node {
                    match *material {
                        material::Material::Sprite(ref mut params) => params.map.set_texel_range(base, size),
                        _ => panic!("Unsupported material for texel range request"),
                    }
                },
                Operation::SetText(operation) => if let SubNode::UiText(ref mut data) = node.sub_node {
                    Hub::process_text(operation, data);
                },
                Operation::SetShadow(map, proj) => if let SubNode::Light(ref mut data) = node.sub_node {
                    data.shadow = Some((map, proj));
                },
            }
        }
        self.nodes.sync_pending();
    }

    fn process_audio(
        operation: AudioOperation,
        data: &mut AudioData,
    ) {
        match operation {
            AudioOperation::Append(clip) => data.source.append(clip),
            AudioOperation::Pause => data.source.pause(),
            AudioOperation::Resume => data.source.resume(),
            AudioOperation::Stop => data.source.stop(),
            AudioOperation::SetVolume(volume) => data.source.set_volume(volume),
        }
    }

    fn process_text(
        operation: TextOperation,
        data: &mut TextData,
    ) {
        use gfx_glyph::Scale;
        match operation {
            TextOperation::Color(color) => {
                let rgb = color::to_linear_rgb(color);
                data.section.color = [rgb[0], rgb[1], rgb[2], 0.0];
            }
            TextOperation::Font(font) => data.font = font,
            TextOperation::Layout(layout) => data.layout = layout,
            TextOperation::Opacity(opacity) => data.section.color[3] = opacity,
            TextOperation::Pos(point) => data.section.screen_position = (point.x, point.y),
            // TODO: somehow grab window::hdpi_factor and multiply size
            TextOperation::Scale(scale) => data.section.scale = Scale::uniform(scale),
            TextOperation::Size(size) => data.section.bounds = (size.x, size.y),
            TextOperation::Text(text) => data.section.text = text,
        }
    }

    pub(crate) fn update_graph(&mut self) {
        let mut cursor = self.nodes.cursor();
        while let Some((left, mut item, _)) = cursor.next() {
            if !item.visible {
                item.world_visible = false;
                continue;
            }
            let (visibility, affilation, transform) = match item.parent {
                Some(ref parent_ptr) => match left.get(parent_ptr) {
                    Some(parent) => (
                        parent.world_visible,
                        parent.scene_id,
                        parent.world_transform.concat(&item.transform),
                    ),
                    None => {
                        error!("Parent node was created after the child, ignoring");
                        (false, item.scene_id, item.transform)
                    }
                },
                None => (true, item.scene_id, item.transform),
            };
            item.world_visible = visibility;
            item.scene_id = affilation;
            item.world_transform = transform;
        }
    }

    pub(crate) fn update_mesh(
        &mut self,
        mesh: &DynamicMesh,
    ) {
        match self.nodes[&mesh.node].sub_node {
            SubNode::Visual(_, ref mut gpu_data) => gpu_data.pending = Some(mesh.dynamic.clone()),
            _ => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::str::FromStr;
use std::default::Default;
use std::ascii::AsciiExt;

macro_rules! inspect(
    ($s:expr, $t:expr) => ({
        let t = $t;
        t
    })
);

macro_rules! enoom {
    (pub enum $en:ident; $ext:ident; $($ty:ident, $text:expr;)*) => (

        #[derive(Clone, Show)]
        pub enum $en {
            $($ty),*,
            $ext(String)
        }

        impl PartialEq for $en {
            fn eq(&self, other: &$en) -> bool {
                match (self, other) {
                    $( (&$en::$ty, &$en::$ty) => true ),*,
                    (&$en::$ext(ref a), &$en::$ext(ref b)) => a == b,
                    _ => self.to_string() == other.to_string()
                }
            }
        }

        impl fmt::String for $en {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str(match *self {
                    $($en::$ty => $text),*,
                    $en::$ext(ref s) => &**s
                })
            }
        }

        impl FromStr for $en {
            fn from_str(s: &str) -> Option<$en> {
                Some(match s {
                    $(_s if _s == $text.to_ascii_lowercase() => $en::$ty),*,
                    s => $en::$ext(inspect!(stringify!($ext), s).to_string())
                })
            }
        }
    )
}

enoom! {
    pub enum Language;
    Ext;
    Ar, "ar";
    De, "de";
    En, "en";
    Fr, "fr";
    Sl, "sl";
}

enoom! {
    pub enum Extlang;
    Ext;
    Yue, "yue";
    Afb, "afb";
}

enoom! {
    pub enum Script;
    Ext;
    Hans, "Hans";
    Latn, "Latn";
}

enoom! {
    pub enum Region;
    Ext;
    De, "DE";
    Fr, "FR";
    It, "IT";
    R005, "005";
}

enoom! {
    pub enum Variant;
    Ext;
    Nedis, "nedis";
}

#[derive(Show, PartialEq, Clone)]
pub struct LanguageTag {
    language: Option<Language>,
    extlang: Option<Extlang>,
    script: Option<Script>,
    region: Option<Region>,
    variants: Vec<Variant>
}

impl LanguageTag {
    // Client: en-GB; matches: en-GB
    // Client: en; matches: en-US
    // TODO: Match canonical forms?
    fn matches(&self, other: &LanguageTag) -> bool {
        if self.language.is_some() && self.language != other.language {
            return false;
        } else if self.extlang.is_some() && self.extlang != other.extlang {
            return false;
        }  else if self.script.is_some() && self.script != other.script {
            return false;
        } else if self.region.is_some() && self.region != other.region {
            return false;
        }
        self.variants.iter().all(|v: &Variant| other.variants.iter().any(|o: &Variant| v == o))
    }
}

impl Default for LanguageTag {
    fn default() -> LanguageTag {
        LanguageTag{
            language: None,
            extlang: None,
            script: None,
            region: None,
            variants: vec![]}
    }
}

fn is_number(string: &str) -> bool {
    string.chars().any(|c| c.is_digit(10))
}

impl std::str::FromStr for LanguageTag {
    fn from_str(s: &str) -> Option<Self> {
        match s.is_ascii() {
            true => {
                let mut tag: LanguageTag = Default::default();
                let a = s.to_ascii_lowercase();
                for (i, code) in a.split('-').enumerate() {
                    if i == 0 {
                        tag.language = code.parse();
                    } else if i == 1 && code.len() == 3 && !(is_number(code)) {
                        tag.extlang = code.parse();
                    } else if code.len() == 4 {
                        tag.script = code.parse();
                    } else if (code.len() == 2 && !(is_number(code))) ||
                            (code.len() == 3 && is_number(code)) {
                        tag.region = code.parse();
                    } else if code.len() > 3 {
                        match code.parse::<Variant>() {
                            Some(v) => tag.variants.push(v),
                            None => {},
                            }
                    } else {
                        return None;
                    }
                }
                Some(tag)
            },
            false => None,
        }

    }
}

impl fmt::String for LanguageTag {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut parts = vec![];
        match self.language {
            Some(ref language) => parts.push(format!("{}", language)),
            None => {},
        }
        match self.extlang {
            Some(ref extlang) => parts.push(format!("{}", extlang)),
            None => {},
        }
        match self.script {
            Some(ref script) => parts.push(format!("{}", script)),
            None => {},
        }
        match self.region {
            Some(ref region) => parts.push(format!("{}", region)),
            None => {},
        }
        for variant in self.variants.iter() {
            parts.push(format!("{}", variant))
        }
        let last = parts.len() - 1;
        for (i, part) in parts.iter().enumerate() {
            try!(write!(f, "{}", part));
            if i < last {
                try!(write!(f, "-"));
            }
        }
        Ok(())
    }
}

mod tests {
    use std::default::Default;
    use super::*;
    // All tests here may be completly nonsensical.
    #[test]
    fn test_lang_from_str() {
        let a: LanguageTag = "de".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::De);
        assert_eq!(a, b);
    }

    #[test]
    fn test_extlang_from_str() {
        let a: LanguageTag = "ar-afb".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Ar);
        b.extlang = Some(Extlang::Afb);
        assert_eq!(a, b);
    }

    #[test]
    fn test_script_from_str() {
        let a: LanguageTag = "ar-afb-Latn".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Ar);
        b.extlang = Some(Extlang::Afb);
        b.script = Some(Script::Latn);
        assert_eq!(a, b);
    }

    #[test]
    fn test_region_from_str() {
        let a: LanguageTag = "ar-DE".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Ar);
        b.region = Some(Region::De);
        assert_eq!(a, b);
    }

    #[test]
    fn test_region_from_str_2() {
        let a: LanguageTag = "ar-005".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Ar);
        b.region = Some(Region::R005);
        assert_eq!(a, b);
    }

    #[test]
    fn test_variant_from_str() {
        let a: LanguageTag = "sl-IT-nedis".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Sl);
        b.region = Some(Region::It);
        b.variants = vec![Variant::Nedis];
        assert_eq!(a, b);
    }

    #[test]
    fn test_invalid_from_str() {
        assert_eq!("sl-07".parse::<LanguageTag>(), None);
    }

    #[test]
    fn test_strange_case_from_str() {
        // This is a perfectly valid language code
        let a: LanguageTag = "SL-AFB-lATN-005-nEdis".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Sl);
        b.extlang = Some(Extlang::Afb);
        b.script = Some(Script::Latn);
        b.region = Some(Region::R005);
        b.variants = vec![Variant::Nedis];
        assert_eq!(a, b);
    }

    #[test]
    fn test_fmt() {
        let a: LanguageTag = "ar-arb-Latn-DE-nedis-foobar".parse().unwrap();
        assert_eq!(format!("{}", a), "ar-arb-Latn-DE-nedis-foobar");
    }

    #[test]
    fn test_match() {
        let de_de: LanguageTag = "de-DE".parse().unwrap();
        let de: LanguageTag = "de".parse().unwrap();
        assert!(de.matches(&de_de));
        assert!(!de_de.matches(&de));
    }
}
<commit_msg>feat(data): Add all known scripts.<commit_after>use std::fmt;
use std::str::FromStr;
use std::default::Default;
use std::ascii::AsciiExt;

macro_rules! inspect(
    ($s:expr, $t:expr) => ({
        let t = $t;
        t
    })
);

macro_rules! enoom {
    (pub enum $en:ident; $ext:ident; $($ty:ident, $text:expr;)*) => (

        #[derive(Clone, Show)]
        pub enum $en {
            $($ty),*,
            $ext(String)
        }

        impl PartialEq for $en {
            fn eq(&self, other: &$en) -> bool {
                match (self, other) {
                    $( (&$en::$ty, &$en::$ty) => true ),*,
                    (&$en::$ext(ref a), &$en::$ext(ref b)) => a == b,
                    _ => self.to_string() == other.to_string()
                }
            }
        }

        impl fmt::String for $en {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str(match *self {
                    $($en::$ty => $text),*,
                    $en::$ext(ref s) => &**s
                })
            }
        }

        impl FromStr for $en {
            fn from_str(s: &str) -> Option<$en> {
                Some(match s {
                    $(_s if _s == $text.to_ascii_lowercase() => $en::$ty),*,
                    s => $en::$ext(inspect!(stringify!($ext), s).to_string())
                })
            }
        }
    )
}

enoom! {
    pub enum Language;
    Ext;
    Ar, "ar";
    De, "de";
    En, "en";
    Fr, "fr";
    Sl, "sl";
}

enoom! {
    pub enum Extlang;
    Ext;
    Yue, "yue";
    Afb, "afb";
}

enoom! {
    pub enum Script;
    Ext;
    Adlm, "Adlm";
    Afak, "Afak";
    Aghb, "Aghb";
    Ahom, "Ahom";
    Arab, "Arab";
    Aran, "Aran";
    Armi, "Armi";
    Armn, "Armn";
    Avst, "Avst";
    Bali, "Bali";
    Bamu, "Bamu";
    Bass, "Bass";
    Batk, "Batk";
    Beng, "Beng";
    Blis, "Blis";
    Bopo, "Bopo";
    Brah, "Brah";
    Brai, "Brai";
    Bugi, "Bugi";
    Buhd, "Buhd";
    Cakm, "Cakm";
    Cans, "Cans";
    Cari, "Cari";
    Cham, "Cham";
    Cher, "Cher";
    Cirt, "Cirt";
    Copt, "Copt";
    Cprt, "Cprt";
    Cyrl, "Cyrl";
    Cyrs, "Cyrs";
    Deva, "Deva";
    Dsrt, "Dsrt";
    Dupl, "Dupl";
    Egyd, "Egyd";
    Egyh, "Egyh";
    Egyp, "Egyp";
    Elba, "Elba";
    Ethi, "Ethi";
    Geok, "Geok";
    Geor, "Geor";
    Glag, "Glag";
    Goth, "Goth";
    Gran, "Gran";
    Grek, "Grek";
    Gujr, "Gujr";
    Guru, "Guru";
    Hang, "Hang";
    Hani, "Hani";
    Hano, "Hano";
    Hans, "Hans";
    Hant, "Hant";
    Hatr, "Hatr";
    Hebr, "Hebr";
    Hira, "Hira";
    Hluw, "Hluw";
    Hmng, "Hmng";
    Hrkt, "Hrkt";
    Hung, "Hung";
    Inds, "Inds";
    Ital, "Ital";
    Java, "Java";
    Jpan, "Jpan";
    Jurc, "Jurc";
    Kali, "Kali";
    Kana, "Kana";
    Khar, "Khar";
    Khmr, "Khmr";
    Khoj, "Khoj";
    Kitl, "Kitl";
    Kits, "Kits";
    Knda, "Knda";
    Kore, "Kore";
    Kpel, "Kpel";
    Kthi, "Kthi";
    Lana, "Lana";
    Laoo, "Laoo";
    Latf, "Latf";
    Latg, "Latg";
    Latn, "Latn";
    Lepc, "Lepc";
    Limb, "Limb";
    Lina, "Lina";
    Linb, "Linb";
    Lisu, "Lisu";
    Loma, "Loma";
    Lyci, "Lyci";
    Lydi, "Lydi";
    Mahj, "Mahj";
    Mand, "Mand";
    Mani, "Mani";
    Marc, "Marc";
    Maya, "Maya";
    Mend, "Mend";
    Merc, "Merc";
    Mero, "Mero";
    Mlym, "Mlym";
    Modi, "Modi";
    Mong, "Mong";
    Moon, "Moon";
    Mroo, "Mroo";
    Mtei, "Mtei";
    Mult, "Mult";
    Mymr, "Mymr";
    Narb, "Narb";
    Nbat, "Nbat";
    Nkgb, "Nkgb";
    Nkoo, "Nkoo";
    Nshu, "Nshu";
    Ogam, "Ogam";
    Olck, "Olck";
    Orkh, "Orkh";
    Orya, "Orya";
    Osge, "Osge";
    Osma, "Osma";
    Palm, "Palm";
    Pauc, "Pauc";
    Perm, "Perm";
    Phag, "Phag";
    Phli, "Phli";
    Phlp, "Phlp";
    Phlv, "Phlv";
    Phnx, "Phnx";
    Plrd, "Plrd";
    Prti, "Prti";
    Rjng, "Rjng";
    Roro, "Roro";
    Runr, "Runr";
    Samr, "Samr";
    Sara, "Sara";
    Sarb, "Sarb";
    Saur, "Saur";
    Sgnw, "Sgnw";
    Shaw, "Shaw";
    Shrd, "Shrd";
    Sidd, "Sidd";
    Sind, "Sind";
    Sinh, "Sinh";
    Sora, "Sora";
    Sund, "Sund";
    Sylo, "Sylo";
    Syrc, "Syrc";
    Syre, "Syre";
    Syrj, "Syrj";
    Syrn, "Syrn";
    Tagb, "Tagb";
    Takr, "Takr";
    Tale, "Tale";
    Talu, "Talu";
    Taml, "Taml";
    Tang, "Tang";
    Tavt, "Tavt";
    Telu, "Telu";
    Teng, "Teng";
    Tfng, "Tfng";
    Tglg, "Tglg";
    Thaa, "Thaa";
    Thai, "Thai";
    Tibt, "Tibt";
    Tirh, "Tirh";
    Ugar, "Ugar";
    Vaii, "Vaii";
    Visp, "Visp";
    Wara, "Wara";
    Wole, "Wole";
    Xpeo, "Xpeo";
    Xsux, "Xsux";
    Yiii, "Yiii";
    Zinh, "Zinh";
    Zmth, "Zmth";
    Zsym, "Zsym";
    Zxxx, "Zxxx";
    Zyyy, "Zyyy";
    Zzzz, "Zzzz";
}

enoom! {
    pub enum Region;
    Ext;
    De, "DE";
    Fr, "FR";
    It, "IT";
    R005, "005";
}

enoom! {
    pub enum Variant;
    Ext;
    Nedis, "nedis";
}

#[derive(Show, PartialEq, Clone)]
pub struct LanguageTag {
    language: Option<Language>,
    extlang: Option<Extlang>,
    script: Option<Script>,
    region: Option<Region>,
    variants: Vec<Variant>
}

impl LanguageTag {
    // Client: en-GB; matches: en-GB
    // Client: en; matches: en-US
    // TODO: Match canonical forms?
    fn matches(&self, other: &LanguageTag) -> bool {
        if self.language.is_some() && self.language != other.language {
            return false;
        } else if self.extlang.is_some() && self.extlang != other.extlang {
            return false;
        }  else if self.script.is_some() && self.script != other.script {
            return false;
        } else if self.region.is_some() && self.region != other.region {
            return false;
        }
        self.variants.iter().all(|v: &Variant| other.variants.iter().any(|o: &Variant| v == o))
    }
}

impl Default for LanguageTag {
    fn default() -> LanguageTag {
        LanguageTag{
            language: None,
            extlang: None,
            script: None,
            region: None,
            variants: vec![]}
    }
}

fn is_number(string: &str) -> bool {
    string.chars().any(|c| c.is_digit(10))
}

impl std::str::FromStr for LanguageTag {
    fn from_str(s: &str) -> Option<Self> {
        match s.is_ascii() {
            true => {
                let mut tag: LanguageTag = Default::default();
                let a = s.to_ascii_lowercase();
                for (i, code) in a.split('-').enumerate() {
                    if i == 0 {
                        tag.language = code.parse();
                    } else if i == 1 && code.len() == 3 && !(is_number(code)) {
                        tag.extlang = code.parse();
                    } else if code.len() == 4 {
                        tag.script = code.parse();
                    } else if (code.len() == 2 && !(is_number(code))) ||
                            (code.len() == 3 && is_number(code)) {
                        tag.region = code.parse();
                    } else if code.len() > 3 {
                        match code.parse::<Variant>() {
                            Some(v) => tag.variants.push(v),
                            None => {},
                            }
                    } else {
                        return None;
                    }
                }
                Some(tag)
            },
            false => None,
        }

    }
}

impl fmt::String for LanguageTag {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut parts = vec![];
        match self.language {
            Some(ref language) => parts.push(format!("{}", language)),
            None => {},
        }
        match self.extlang {
            Some(ref extlang) => parts.push(format!("{}", extlang)),
            None => {},
        }
        match self.script {
            Some(ref script) => parts.push(format!("{}", script)),
            None => {},
        }
        match self.region {
            Some(ref region) => parts.push(format!("{}", region)),
            None => {},
        }
        for variant in self.variants.iter() {
            parts.push(format!("{}", variant))
        }
        let last = parts.len() - 1;
        for (i, part) in parts.iter().enumerate() {
            try!(write!(f, "{}", part));
            if i < last {
                try!(write!(f, "-"));
            }
        }
        Ok(())
    }
}

mod tests {
    use std::default::Default;
    use super::*;
    // All tests here may be completly nonsensical.
    #[test]
    fn test_lang_from_str() {
        let a: LanguageTag = "de".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::De);
        assert_eq!(a, b);
    }

    #[test]
    fn test_extlang_from_str() {
        let a: LanguageTag = "ar-afb".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Ar);
        b.extlang = Some(Extlang::Afb);
        assert_eq!(a, b);
    }

    #[test]
    fn test_script_from_str() {
        let a: LanguageTag = "ar-afb-Latn".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Ar);
        b.extlang = Some(Extlang::Afb);
        b.script = Some(Script::Latn);
        assert_eq!(a, b);
    }

    #[test]
    fn test_region_from_str() {
        let a: LanguageTag = "ar-DE".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Ar);
        b.region = Some(Region::De);
        assert_eq!(a, b);
    }

    #[test]
    fn test_region_from_str_2() {
        let a: LanguageTag = "ar-005".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Ar);
        b.region = Some(Region::R005);
        assert_eq!(a, b);
    }

    #[test]
    fn test_variant_from_str() {
        let a: LanguageTag = "sl-IT-nedis".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Sl);
        b.region = Some(Region::It);
        b.variants = vec![Variant::Nedis];
        assert_eq!(a, b);
    }

    #[test]
    fn test_invalid_from_str() {
        assert_eq!("sl-07".parse::<LanguageTag>(), None);
    }

    #[test]
    fn test_strange_case_from_str() {
        // This is a perfectly valid language code
        let a: LanguageTag = "SL-AFB-lATN-005-nEdis".parse().unwrap();
        let mut b: LanguageTag = Default::default();
        b.language = Some(Language::Sl);
        b.extlang = Some(Extlang::Afb);
        b.script = Some(Script::Latn);
        b.region = Some(Region::R005);
        b.variants = vec![Variant::Nedis];
        assert_eq!(a, b);
    }

    #[test]
    fn test_fmt() {
        let a: LanguageTag = "ar-arb-Latn-DE-nedis-foobar".parse().unwrap();
        assert_eq!(format!("{}", a), "ar-arb-Latn-DE-nedis-foobar");
    }

    #[test]
    fn test_match() {
        let de_de: LanguageTag = "de-DE".parse().unwrap();
        let de: LanguageTag = "de".parse().unwrap();
        assert!(de.matches(&de_de));
        assert!(!de_de.matches(&de));
    }
}
<|endoftext|>


<commit_before>#[test]
fn it_works() {
}
<commit_msg>Removed placeholder test.<commit_after><|endoftext|>


<commit_before>//! libc - Raw FFI bindings to platforms' system libraries
//!
//! [Documentation for other platforms][pd].
//!
//! [pd]: https://rust-lang.github.io/libc/#platform-specific-documentation
#![crate_name = "libc"]
#![crate_type = "rlib"]
// FIXME: Remove this and redundant_semicolon once renamed lint reaches stable.
#![allow(renamed_and_removed_lints)]
#![allow(
    bad_style,
    overflowing_literals,
    improper_ctypes,
    unknown_lints,
    redundant_semicolon,
    redundant_semicolons
)]
#![cfg_attr(libc_deny_warnings, deny(warnings))]
// Attributes needed when building as part of the standard library
#![cfg_attr(
    feature = "rustc-dep-of-std",
    feature(cfg_target_vendor, link_cfg, no_core)
)]
#![cfg_attr(libc_thread_local, feature(thread_local))]
// Enable extra lints:
#![cfg_attr(feature = "extra_traits", deny(missing_debug_implementations))]
#![deny(missing_copy_implementations, safe_packed_borrows)]
#![no_std]
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
#![cfg_attr(target_os = "redox", feature(static_nobundle))]
#![cfg_attr(libc_const_extern_fn, feature(const_extern_fn))]

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(feature = "rustc-dep-of-std")] {
        extern crate rustc_std_workspace_core as core;
        #[allow(unused_imports)]
        use core::iter;
        #[allow(unused_imports)]
        use core::ops;
        #[allow(unused_imports)]
        use core::option;
    }
}

cfg_if! {
    if #[cfg(libc_priv_mod_use)] {
        #[cfg(libc_core_cvoid)]
        #[allow(unused_imports)]
        use core::ffi;
        #[allow(unused_imports)]
        use core::fmt;
        #[allow(unused_imports)]
        use core::hash;
        #[allow(unused_imports)]
        use core::num;
        #[allow(unused_imports)]
        use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::marker::Copy;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::option::Option;
    } else {
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::fmt;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::hash;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::num;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::marker::Copy;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::option::Option;
    }
}

cfg_if! {
    if #[cfg(windows)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod windows;
        pub use windows::*;
    } else if #[cfg(target_os = "cloudabi")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod cloudabi;
        pub use cloudabi::*;
    } else if #[cfg(target_os = "fuchsia")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod fuchsia;
        pub use fuchsia::*;
    } else if #[cfg(target_os = "switch")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod switch;
        pub use switch::*;
    } else if #[cfg(target_os = "psp")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod psp;
        pub use psp::*;
    } else if #[cfg(target_os = "vxworks")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod vxworks;
        pub use vxworks::*;
    } else if #[cfg(unix)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod unix;
        pub use unix::*;
    } else if #[cfg(target_os = "hermit")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod hermit;
        pub use hermit::*;
    } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod sgx;
        pub use sgx::*;
    } else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod wasi;
        pub use wasi::*;
    } else {
        // non-supported targets: empty...
    }
}
<commit_msg>Update comment to clarify<commit_after>//! libc - Raw FFI bindings to platforms' system libraries
//!
//! [Documentation for other platforms][pd].
//!
//! [pd]: https://rust-lang.github.io/libc/#platform-specific-documentation
#![crate_name = "libc"]
#![crate_type = "rlib"]
#![allow(
    bad_style,
    overflowing_literals,
    improper_ctypes,
    // This lint is renamed but we run CI for old stable rustc so should be here.
    redundant_semicolon,
    redundant_semicolons,
    renamed_and_removed_lints,
    unknown_lints
)]
#![cfg_attr(libc_deny_warnings, deny(warnings))]
// Attributes needed when building as part of the standard library
#![cfg_attr(
    feature = "rustc-dep-of-std",
    feature(cfg_target_vendor, link_cfg, no_core)
)]
#![cfg_attr(libc_thread_local, feature(thread_local))]
// Enable extra lints:
#![cfg_attr(feature = "extra_traits", deny(missing_debug_implementations))]
#![deny(missing_copy_implementations, safe_packed_borrows)]
#![no_std]
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
#![cfg_attr(target_os = "redox", feature(static_nobundle))]
#![cfg_attr(libc_const_extern_fn, feature(const_extern_fn))]

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(feature = "rustc-dep-of-std")] {
        extern crate rustc_std_workspace_core as core;
        #[allow(unused_imports)]
        use core::iter;
        #[allow(unused_imports)]
        use core::ops;
        #[allow(unused_imports)]
        use core::option;
    }
}

cfg_if! {
    if #[cfg(libc_priv_mod_use)] {
        #[cfg(libc_core_cvoid)]
        #[allow(unused_imports)]
        use core::ffi;
        #[allow(unused_imports)]
        use core::fmt;
        #[allow(unused_imports)]
        use core::hash;
        #[allow(unused_imports)]
        use core::num;
        #[allow(unused_imports)]
        use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::marker::Copy;
        #[doc(hidden)]
        #[allow(unused_imports)]
        use core::option::Option;
    } else {
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::fmt;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::hash;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::num;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::mem;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::clone::Clone;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::marker::Copy;
        #[doc(hidden)]
        #[allow(unused_imports)]
        pub use core::option::Option;
    }
}

cfg_if! {
    if #[cfg(windows)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod windows;
        pub use windows::*;
    } else if #[cfg(target_os = "cloudabi")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod cloudabi;
        pub use cloudabi::*;
    } else if #[cfg(target_os = "fuchsia")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod fuchsia;
        pub use fuchsia::*;
    } else if #[cfg(target_os = "switch")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod switch;
        pub use switch::*;
    } else if #[cfg(target_os = "psp")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod psp;
        pub use psp::*;
    } else if #[cfg(target_os = "vxworks")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod vxworks;
        pub use vxworks::*;
    } else if #[cfg(unix)] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod unix;
        pub use unix::*;
    } else if #[cfg(target_os = "hermit")] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod hermit;
        pub use hermit::*;
    } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod sgx;
        pub use sgx::*;
    } else if #[cfg(any(target_env = "wasi", target_os = "wasi"))] {
        mod fixed_width_ints;
        pub use fixed_width_ints::*;

        mod wasi;
        pub use wasi::*;
    } else {
        // non-supported targets: empty...
    }
}
<|endoftext|>


<commit_before>#![crate_id = "discotech"]
#![crate_type = "lib"]
#![feature(libc)]
extern crate libc;

use libc::types::os::common::bsd44::{socklen_t, sockaddr};
use libc::{c_char, c_int, c_void};
use std::mem;

#[link(name="dl")]
extern {
    fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void;
}
const RTLD_NEXT: *const c_void = -1isize as *const c_void;
pub unsafe fn dlsym_next(symbol: &'static str) -> *const u8 {
    let ptr = dlsym(RTLD_NEXT, symbol.as_ptr() as *const c_char);
    if ptr.is_null() {
        panic!("discotech: Unable to find underlying function for {}", symbol);
    }
    ptr as *const u8
}

static mut real_connect : Option<fn(c_int, *const sockaddr, socklen_t) -> c_int> = None;
#[no_mangle]
pub unsafe extern "C" fn connect(socket: c_int, address: *const sockaddr,
                           len: socklen_t) -> c_int {
    println!("HOOKING CONNECT!!!!!!!!!!!!!!!!!");
    let f = match real_connect {
        Some(f) => f,
        None => {
            let ptr = dlsym_next("connect");
            let f: &mut fn(c_int, *const sockaddr, socklen_t) -> c_int = mem::transmute(ptr);
            real_connect = Some(*f);
            *f
        }
    };
    f(socket, address, len)
}

#[no_mangle]
pub extern "C" fn _init() {
    println!("in _init!!!!");
}

#[test]
fn lookup() {
    println!("lookup: {:?}", unsafe { dlsym_next("puts") });
    unsafe { connect(0, 0 as *const sockaddr, 4 as socklen_t); }
}
<commit_msg>fix osx hooking<commit_after>#![crate_id = "discotech"]
#![crate_type = "lib"]
#![feature(libc)]
extern crate libc;

use libc::types::os::common::bsd44::{socklen_t, sockaddr};
use libc::{c_char, c_int, c_void};
use std::mem;

#[link(name="dl")]
extern {
    fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void;
}
const RTLD_NEXT: *const c_void = -1isize as *const c_void;
pub unsafe fn dlsym_next(symbol: &'static str) -> *const u8 {
    let ptr = dlsym(RTLD_NEXT, symbol.as_ptr() as *const c_char);
    if ptr.is_null() {
        panic!("discotech: Unable to find underlying function for {}", symbol);
    }
    ptr as *const u8
}

#[no_mangle]
pub unsafe extern "C" fn connect(socket: c_int, address: *const sockaddr,
                           len: socklen_t) -> c_int {
    println!("HOOKING CONNECT!!!!!!!!!!!!!!!!!");
    let ptr = dlsym_next("connect");
    let f: fn(c_int, *const sockaddr, socklen_t) -> c_int = mem::transmute(ptr);
    f(socket, address, len)
}
<|endoftext|>


<commit_before><commit_msg>ENH: serializable port borrows<commit_after><|endoftext|>


<commit_before>extern crate graphics;

use graphics::{ Context, Graphics };

pub struct Timeline {
    pub frames: u32,
    pub current_frame: u32,
    pub bounds: [u32; 4],
}

impl Timeline {
    pub fn new_frames_bounds(frames: u32, bounds: [u32; 4]) -> Timeline {
        Timeline {
            frames: frames,
            current_frame: 0,
            bounds: bounds,
        }
    }

    pub fn draw_timeline<G: Graphics>(&self, c: &Context, g: &mut G) {
        let left_to_frame: f64 = 20.0;
        let top_to_frame: f64 = 15.0;
        let frame_width: f64 = 10.0;
        let frame_height: f64 = 10.0;
        let frame_offset_x: f64 = 5.0;
        let slide_offset: f64 = 0.0;
        let left_to_goto_beginning: f64 = 15.0;
        let right_to_goto_end: f64 = 15.0;

        // Draw bounds to see where the control is.
        {
            use graphics::Rectangle;

            let bounds = [
                    self.bounds[0] as f64,
                    self.bounds[1] as f64,
                    self.bounds[2] as f64,
                    self.bounds[3] as f64
                ];
            Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5)
                .draw(bounds, &c.draw_state, c.transform, g);
        }

        // Draw a sequence of squares for each frame.
        {
            use graphics::Rectangle;

            let rect = Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5);
            for i in 0..self.frames {
                let bounds = [
                    self.bounds[0] as f64 + left_to_frame
                        + i as f64 * (frame_width + frame_offset_x)
                        - slide_offset,
                    self.bounds[1] as f64 + top_to_frame,
                    frame_width,
                    frame_height
                ];
                rect.draw(bounds, &c.draw_state, c.transform, g);
            }
        }

        // Draw navigate to beginning button.
        {
            fn draw_triangle<G: Graphics>(
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                use graphics::math::*;

                let triangle = [
                    [0.0, 0.0],
                    [1.0, 0.5],
                    [0.0, 1.0]
                ];
                let transform_triangle = multiply(
                    translate(offset),
                    scale(scale_up[0], scale_up[1])
                );
                let p = [
                    transform_pos(transform_triangle, triangle[0]),
                    transform_pos(transform_triangle, triangle[1]),
                    transform_pos(transform_triangle, triangle[2])
                ];
                for i in 0..3 {
                    let j = (i + 1) % 3;
                    line.draw([p[i][0], p[i][1], p[j][0], p[j][1]], &c.draw_state, c.transform, g);
                }
            }

            fn draw_double_arrow<G: Graphics>(
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                draw_triangle(offset, scale_up, line, c, g);
                let offset = [offset[0] + scale_up[0], offset[1]];
                draw_triangle(offset, scale_up, line, c, g);
            }

            fn draw_goto_end<G: Graphics>(
                at_end: bool,
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                if !at_end {
                    draw_triangle(offset, scale_up, line, c, g);
                }

                line.draw([
                    offset[0] + scale_up[0], offset[1],
                    offset[0] + scale_up[0], offset[1] + scale_up[1]
                ], &c.draw_state, c.transform, g);
            }

            use graphics::Line;
            use graphics::math::*;

            let line = Line::new([0.0, 0.0, 1.0, 1.0], 0.5);

            let at_beginning: bool = false;
            draw_goto_end(
                at_beginning,
                [
                    self.bounds[0] as f64 + left_to_goto_beginning,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    -frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );

            let at_end: bool = true;
            draw_goto_end(
                at_end,
                [
                    self.bounds[0] as f64 + self.bounds[2] as f64
                        - right_to_goto_end,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );
        }
    }

    pub fn draw_drag<G: Graphics>(&self, c: &Context, g: &mut G) {

    }
}
<commit_msg>Compute max visible frames<commit_after>extern crate graphics;

use graphics::{ Context, Graphics };

pub struct Timeline {
    pub frames: u32,
    pub current_frame: u32,
    pub bounds: [u32; 4],
}

impl Timeline {
    pub fn new_frames_bounds(frames: u32, bounds: [u32; 4]) -> Timeline {
        Timeline {
            frames: frames,
            current_frame: 0,
            bounds: bounds,
        }
    }

    pub fn draw_timeline<G: Graphics>(&self, c: &Context, g: &mut G) {
        let left_to_frame: f64 = 20.0;
        let right_to_frame: f64 = 20.0;
        let top_to_frame: f64 = 15.0;
        let frame_width: f64 = 10.0;
        let frame_height: f64 = 10.0;
        let frame_offset_x: f64 = 5.0;
        let slide_offset: f64 = 0.0;
        let left_to_goto_beginning: f64 = 15.0;
        let right_to_goto_end: f64 = 15.0;
        let width_for_frames = self.bounds[2] as f64
            - left_to_frame - right_to_frame;
        let max_visible_frames: u32 =
            if width_for_frames < frame_width {
                0
            } else {
                1
                + (
                    (width_for_frames - frame_width)
                    / (frame_width + frame_offset_x)
                ) as u32
            };

        // Draw bounds to see where the control is.
        {
            use graphics::Rectangle;

            let bounds = [
                    self.bounds[0] as f64,
                    self.bounds[1] as f64,
                    self.bounds[2] as f64,
                    self.bounds[3] as f64
                ];
            Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5)
                .draw(bounds, &c.draw_state, c.transform, g);
        }

        // Draw a sequence of squares for each frame.
        {
            use graphics::Rectangle;

            let rect = Rectangle::new_border([0.0, 0.0, 1.0, 1.0], 0.5);
            for i in 0..self.frames {
                let bounds = [
                    self.bounds[0] as f64 + left_to_frame
                        + i as f64 * (frame_width + frame_offset_x)
                        - slide_offset,
                    self.bounds[1] as f64 + top_to_frame,
                    frame_width,
                    frame_height
                ];
                rect.draw(bounds, &c.draw_state, c.transform, g);
            }
        }

        // Draw navigate to beginning button.
        {
            fn draw_triangle<G: Graphics>(
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                use graphics::math::*;

                let triangle = [
                    [0.0, 0.0],
                    [1.0, 0.5],
                    [0.0, 1.0]
                ];
                let transform_triangle = multiply(
                    translate(offset),
                    scale(scale_up[0], scale_up[1])
                );
                let p = [
                    transform_pos(transform_triangle, triangle[0]),
                    transform_pos(transform_triangle, triangle[1]),
                    transform_pos(transform_triangle, triangle[2])
                ];
                for i in 0..3 {
                    let j = (i + 1) % 3;
                    line.draw([p[i][0], p[i][1], p[j][0], p[j][1]], &c.draw_state, c.transform, g);
                }
            }

            fn draw_double_arrow<G: Graphics>(
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                draw_triangle(offset, scale_up, line, c, g);
                let offset = [offset[0] + scale_up[0], offset[1]];
                draw_triangle(offset, scale_up, line, c, g);
            }

            fn draw_goto_end<G: Graphics>(
                at_end: bool,
                offset: graphics::math::Vec2d,
                scale_up: graphics::math::Vec2d,
                line: &Line,
                c: &Context,
                g: &mut G
            ) {
                if !at_end {
                    draw_triangle(offset, scale_up, line, c, g);
                }

                line.draw([
                    offset[0] + scale_up[0], offset[1],
                    offset[0] + scale_up[0], offset[1] + scale_up[1]
                ], &c.draw_state, c.transform, g);
            }

            use graphics::Line;
            use graphics::math::*;

            let line = Line::new([0.0, 0.0, 1.0, 1.0], 0.5);

            let at_beginning: bool = false;
            draw_goto_end(
                at_beginning,
                [
                    self.bounds[0] as f64 + left_to_goto_beginning,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    -frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );

            let at_end: bool = true;
            draw_goto_end(
                at_end,
                [
                    self.bounds[0] as f64 + self.bounds[2] as f64
                        - right_to_goto_end,
                    self.bounds[1] as f64 + top_to_frame
                ],
                [
                    frame_width * 0.5,
                    frame_height
                ],
                &line,
                c, g
            );
        }
    }

    pub fn draw_drag<G: Graphics>(&self, c: &Context, g: &mut G) {

    }
}
<|endoftext|>