<commit_before>use common::conn::Conn;
use common::stream::HttpStreamCommon;
use common::stream::HttpStreamData;
use common::types::Types;
use solicit::StreamId;

use data_or_headers_with_flag::DataOrHeadersWithFlag;

use bytes::Bytes;
use common::conn::ConnStateSnapshot;
use common::conn_read::ConnReadSideCustom;
use common::iteration_exit::IterationExit;
use common::stream::HttpStreamCommand;
use error;
use futures::sync::oneshot;
use futures::task;
use futures::Async;
use futures::Poll;
use result;
use solicit::end_stream::EndStream;
use solicit::frame::flags::Flags;
use solicit::frame::headers::HeadersMultiFrame;
use solicit::frame::DataFlag;
use solicit::frame::DataFrame;
use solicit::frame::GoawayFrame;
use solicit::frame::HeadersFlag;
use solicit::frame::HttpFrame;
use solicit::frame::RstStreamFrame;
use solicit::frame::SettingsFrame;
use std::cmp;
use ErrorCode;
use Headers;

pub trait ConnWriteSideCustom {
    type Types: Types;

    fn process_message(
        &mut self,
        message: <Self::Types as Types>::ToWriteMessage,
    ) -> result::Result<()>;
}

impl<T> Conn<T>
where
    T: Types,
    Self: ConnReadSideCustom<Types = T>,
    Self: ConnWriteSideCustom<Types = T>,
    HttpStreamCommon<T>: HttpStreamData<Types = T>,
{
    fn write_part_data(&mut self, stream_id: StreamId, data: Bytes, end_stream: EndStream) {
        let max_frame_size = self.peer_settings.max_frame_size as usize;

        // if client requested end of stream,
        // we must send at least one frame with end stream flag
        if end_stream == EndStream::Yes && data.len() == 0 {
            let mut frame = DataFrame::with_data(stream_id, Bytes::new());
            frame.set_flag(DataFlag::EndStream);

            debug!("sending frame {:?}", frame);

            self.queued_write.queue_not_goaway(frame);

            return;
        }

        let mut pos = 0;
        while pos < data.len() {
            let end = cmp::min(data.len(), pos + max_frame_size);

            let end_stream_in_frame = if end == data.len() && end_stream == EndStream::Yes {
                EndStream::Yes
            } else {
                EndStream::No
            };

            let mut frame = DataFrame::with_data(stream_id, data.slice(pos, end));
            if end_stream_in_frame == EndStream::Yes {
                frame.set_flag(DataFlag::EndStream);
            }

            self.queued_write.queue_not_goaway(frame);

            pos = end;
        }
    }

    fn write_part_headers(&mut self, stream_id: StreamId, headers: Headers, end_stream: EndStream) {
        let mut flags = Flags::new(0);
        if end_stream == EndStream::Yes {
            flags.set(HeadersFlag::EndStream);
        }
        self.queued_write.queue_not_goaway(HeadersMultiFrame {
            flags,
            stream_id,
            headers,
            stream_dep: None,
            padding_len: 0,
            encoder: &mut self.encoder,
            max_frame_size: self.peer_settings.max_frame_size,
        });
    }

    fn write_part_rst(&mut self, stream_id: StreamId, error_code: ErrorCode) {
        let frame = RstStreamFrame::new(stream_id, error_code);

        self.queued_write.queue_not_goaway(frame);
    }

    fn write_part(&mut self, stream_id: StreamId, part: HttpStreamCommand) {
        match part {
            HttpStreamCommand::Data(data, end_stream) => {
                self.write_part_data(stream_id, data, end_stream);
            }
            HttpStreamCommand::Headers(headers, end_stream) => {
                self.write_part_headers(stream_id, headers, end_stream);
            }
            HttpStreamCommand::Rst(error_code) => {
                self.write_part_rst(stream_id, error_code);
            }
        }
    }

    fn has_write_buffer_capacity(&self) -> bool {
        self.queued_write.queued_bytes_len() < 0x8000
    }

    fn pop_outg_for_stream(
        &mut self,
        stream_id: StreamId,
    ) -> Option<(StreamId, HttpStreamCommand, bool)> {
        let stream = self.streams.get_mut(stream_id).unwrap();
        if let (Some(command), stream) = stream.pop_outg_maybe_remove(&mut self.out_window_size) {
            return Some((stream_id, command, stream.is_some()));
        }

        None
    }

    pub fn buffer_outg_conn(&mut self) -> result::Result<bool> {
        let mut updated = false;

        // shortcut
        if !self.has_write_buffer_capacity() {
            return Ok(updated);
        }

        let writable_stream_ids = self.streams.writable_stream_ids();

        for &stream_id in &writable_stream_ids {
            loop {
                if !self.has_write_buffer_capacity() {
                    return Ok(updated);
                }

                if let Some((stream_id, part, cont)) = self.pop_outg_for_stream(stream_id) {
                    self.write_part(stream_id, part);
                    updated = true;

                    // Stream is removed from map, need to continue to the next stream
                    if !cont {
                        break;
                    }
                } else {
                    break;
                }
            }
        }

        Ok(updated)
    }

    pub fn send_frame_and_notify<F: Into<HttpFrame>>(&mut self, frame: F) {
        // TODO: some of frames should not be in front of GOAWAY
        self.queued_write.queue_not_goaway(frame.into());
        // Notify the task to make sure write loop is called again
        // to flush the buffer
        task::current().notify();
    }

    /// Sends an SETTINGS Frame with ack set to acknowledge seeing a SETTINGS frame from the peer.
    pub fn send_ack_settings(&mut self) -> result::Result<()> {
        let settings = SettingsFrame::new_ack();
        self.send_frame_and_notify(settings);
        Ok(())
    }

    fn process_stream_end(
        &mut self,
        stream_id: StreamId,
        error_code: ErrorCode,
    ) -> result::Result<()> {
        let stream = self.streams.get_mut(stream_id);
        if let Some(mut stream) = stream {
            stream.close_outgoing(error_code);
        }
        Ok(())
    }

    fn process_stream_enqueue(
        &mut self,
        stream_id: StreamId,
        part: DataOrHeadersWithFlag,
    ) -> result::Result<()> {
        let stream = self.streams.get_mut(stream_id);
        if let Some(mut stream) = stream {
            stream.push_back_part(part);
        }
        Ok(())
    }

    pub fn process_common_message(&mut self, common: CommonToWriteMessage) -> result::Result<()> {
        match common {
            CommonToWriteMessage::StreamEnd(stream_id, error_code) => {
                self.process_stream_end(stream_id, error_code)?;
            }
            CommonToWriteMessage::StreamEnqueue(stream_id, part) => {
                self.process_stream_enqueue(stream_id, part)?;
            }
            CommonToWriteMessage::IncreaseInWindow(stream_id, increase) => {
                self.increase_in_window(stream_id, increase)?;
            }
            CommonToWriteMessage::DumpState(sender) => {
                self.process_dump_state(sender)?;
            }
        }
        Ok(())
    }

    pub fn send_goaway(&mut self, error_code: ErrorCode) -> result::Result<()> {
        debug!("requesting to send GOAWAY with code {:?}", error_code);
        let frame = GoawayFrame::new(self.last_peer_stream_id, error_code);
        self.queued_write.queue_goaway(frame);
        task::current().notify();
        Ok(())
    }

    pub fn process_goaway_state(&mut self) -> result::Result<IterationExit> {
        Ok(if self.queued_write.goaway_queued() {
            self.queued_write.poll()?;
            if self.queued_write.queued_empty() {
                IterationExit::ExitEarly
            } else {
                IterationExit::NotReady
            }
        } else {
            IterationExit::Continue
        })
    }

    fn process_write_queue(&mut self) -> Poll<(), error::Error> {
        loop {
            let message = match self.write_rx.poll()? {
                Async::NotReady => return Ok(Async::NotReady),
                Async::Ready(Some(message)) => message,
                Async::Ready(None) => return Ok(Async::Ready(())), // Add some diagnostics maybe?
            };

            self.process_message(message)?;
        }
    }

    fn poll_flush(&mut self) -> result::Result<()> {
        self.buffer_outg_conn()?;
        loop {
            self.queued_write.poll()?;
            let updated = self.buffer_outg_conn()?;
            if !updated {
                return Ok(());
            }
        }
    }

    pub fn poll_write(&mut self) -> Poll<(), error::Error> {
        if let Async::Ready(()) = self.process_write_queue()? {
            return Ok(Async::Ready(()));
        }

        self.poll_flush()?;

        Ok(Async::NotReady)
    }
}

// Message sent to write loop.
// Processed while write loop is not handling network I/O.
pub enum CommonToWriteMessage {
    IncreaseInWindow(StreamId, u32),
    StreamEnqueue(StreamId, DataOrHeadersWithFlag),
    StreamEnd(StreamId, ErrorCode), // send when user provided handler completed the stream
    DumpState(oneshot::Sender<ConnStateSnapshot>),
}
<commit_msg>Properly release pumped out windows when data is dropped<commit_after>use common::conn::Conn;
use common::stream::HttpStreamCommon;
use common::stream::HttpStreamData;
use common::types::Types;
use solicit::StreamId;

use data_or_headers_with_flag::DataOrHeadersWithFlag;

use bytes::Bytes;
use common::conn::ConnStateSnapshot;
use common::conn_read::ConnReadSideCustom;
use common::iteration_exit::IterationExit;
use common::stream::HttpStreamCommand;
use error;
use futures::sync::oneshot;
use futures::task;
use futures::Async;
use futures::Poll;
use result;
use solicit::end_stream::EndStream;
use solicit::frame::flags::Flags;
use solicit::frame::headers::HeadersMultiFrame;
use solicit::frame::DataFlag;
use solicit::frame::DataFrame;
use solicit::frame::GoawayFrame;
use solicit::frame::HeadersFlag;
use solicit::frame::HttpFrame;
use solicit::frame::RstStreamFrame;
use solicit::frame::SettingsFrame;
use std::cmp;
use ErrorCode;
use Headers;
use data_or_headers::DataOrHeaders;

pub trait ConnWriteSideCustom {
    type Types: Types;

    fn process_message(
        &mut self,
        message: <Self::Types as Types>::ToWriteMessage,
    ) -> result::Result<()>;
}

impl<T> Conn<T>
where
    T: Types,
    Self: ConnReadSideCustom<Types = T>,
    Self: ConnWriteSideCustom<Types = T>,
    HttpStreamCommon<T>: HttpStreamData<Types = T>,
{
    fn write_part_data(&mut self, stream_id: StreamId, data: Bytes, end_stream: EndStream) {
        let max_frame_size = self.peer_settings.max_frame_size as usize;

        // if client requested end of stream,
        // we must send at least one frame with end stream flag
        if end_stream == EndStream::Yes && data.len() == 0 {
            let mut frame = DataFrame::with_data(stream_id, Bytes::new());
            frame.set_flag(DataFlag::EndStream);

            debug!("sending frame {:?}", frame);

            self.queued_write.queue_not_goaway(frame);

            return;
        }

        let mut pos = 0;
        while pos < data.len() {
            let end = cmp::min(data.len(), pos + max_frame_size);

            let end_stream_in_frame = if end == data.len() && end_stream == EndStream::Yes {
                EndStream::Yes
            } else {
                EndStream::No
            };

            let mut frame = DataFrame::with_data(stream_id, data.slice(pos, end));
            if end_stream_in_frame == EndStream::Yes {
                frame.set_flag(DataFlag::EndStream);
            }

            self.queued_write.queue_not_goaway(frame);

            pos = end;
        }
    }

    fn write_part_headers(&mut self, stream_id: StreamId, headers: Headers, end_stream: EndStream) {
        let mut flags = Flags::new(0);
        if end_stream == EndStream::Yes {
            flags.set(HeadersFlag::EndStream);
        }
        self.queued_write.queue_not_goaway(HeadersMultiFrame {
            flags,
            stream_id,
            headers,
            stream_dep: None,
            padding_len: 0,
            encoder: &mut self.encoder,
            max_frame_size: self.peer_settings.max_frame_size,
        });
    }

    fn write_part_rst(&mut self, stream_id: StreamId, error_code: ErrorCode) {
        let frame = RstStreamFrame::new(stream_id, error_code);

        self.queued_write.queue_not_goaway(frame);
    }

    fn write_part(&mut self, stream_id: StreamId, part: HttpStreamCommand) {
        match part {
            HttpStreamCommand::Data(data, end_stream) => {
                self.write_part_data(stream_id, data, end_stream);
            }
            HttpStreamCommand::Headers(headers, end_stream) => {
                self.write_part_headers(stream_id, headers, end_stream);
            }
            HttpStreamCommand::Rst(error_code) => {
                self.write_part_rst(stream_id, error_code);
            }
        }
    }

    fn has_write_buffer_capacity(&self) -> bool {
        self.queued_write.queued_bytes_len() < 0x8000
    }

    fn pop_outg_for_stream(
        &mut self,
        stream_id: StreamId,
    ) -> Option<(StreamId, HttpStreamCommand, bool)> {
        let stream = self.streams.get_mut(stream_id).unwrap();
        if let (Some(command), stream) = stream.pop_outg_maybe_remove(&mut self.out_window_size) {
            return Some((stream_id, command, stream.is_some()));
        }

        None
    }

    pub fn buffer_outg_conn(&mut self) -> result::Result<bool> {
        let mut updated = false;

        // shortcut
        if !self.has_write_buffer_capacity() {
            return Ok(updated);
        }

        let writable_stream_ids = self.streams.writable_stream_ids();

        for &stream_id in &writable_stream_ids {
            loop {
                if !self.has_write_buffer_capacity() {
                    return Ok(updated);
                }

                if let Some((stream_id, part, cont)) = self.pop_outg_for_stream(stream_id) {
                    self.write_part(stream_id, part);
                    updated = true;

                    // Stream is removed from map, need to continue to the next stream
                    if !cont {
                        break;
                    }
                } else {
                    break;
                }
            }
        }

        Ok(updated)
    }

    pub fn send_frame_and_notify<F: Into<HttpFrame>>(&mut self, frame: F) {
        // TODO: some of frames should not be in front of GOAWAY
        self.queued_write.queue_not_goaway(frame.into());
        // Notify the task to make sure write loop is called again
        // to flush the buffer
        task::current().notify();
    }

    /// Sends an SETTINGS Frame with ack set to acknowledge seeing a SETTINGS frame from the peer.
    pub fn send_ack_settings(&mut self) -> result::Result<()> {
        let settings = SettingsFrame::new_ack();
        self.send_frame_and_notify(settings);
        Ok(())
    }

    fn process_stream_end(
        &mut self,
        stream_id: StreamId,
        error_code: ErrorCode,
    ) -> result::Result<()> {
        let stream = self.streams.get_mut(stream_id);
        if let Some(mut stream) = stream {
            stream.close_outgoing(error_code);
        }
        Ok(())
    }

    fn process_stream_enqueue(
        &mut self,
        stream_id: StreamId,
        part: DataOrHeadersWithFlag,
    ) -> result::Result<()> {
        let stream = self.streams.get_mut(stream_id);
        if let Some(mut stream) = stream {
            stream.push_back_part(part);
        } else {
            if let DataOrHeaders::Data(data) = part.content {
                // TODO: integer overflow
                self.pump_out_window_size.increase(data.len() as u32);
            }
        }
        Ok(())
    }

    pub fn process_common_message(&mut self, common: CommonToWriteMessage) -> result::Result<()> {
        match common {
            CommonToWriteMessage::StreamEnd(stream_id, error_code) => {
                self.process_stream_end(stream_id, error_code)?;
            }
            CommonToWriteMessage::StreamEnqueue(stream_id, part) => {
                self.process_stream_enqueue(stream_id, part)?;
            }
            CommonToWriteMessage::IncreaseInWindow(stream_id, increase) => {
                self.increase_in_window(stream_id, increase)?;
            }
            CommonToWriteMessage::DumpState(sender) => {
                self.process_dump_state(sender)?;
            }
        }
        Ok(())
    }

    pub fn send_goaway(&mut self, error_code: ErrorCode) -> result::Result<()> {
        debug!("requesting to send GOAWAY with code {:?}", error_code);
        let frame = GoawayFrame::new(self.last_peer_stream_id, error_code);
        self.queued_write.queue_goaway(frame);
        task::current().notify();
        Ok(())
    }

    pub fn process_goaway_state(&mut self) -> result::Result<IterationExit> {
        Ok(if self.queued_write.goaway_queued() {
            self.queued_write.poll()?;
            if self.queued_write.queued_empty() {
                IterationExit::ExitEarly
            } else {
                IterationExit::NotReady
            }
        } else {
            IterationExit::Continue
        })
    }

    fn process_write_queue(&mut self) -> Poll<(), error::Error> {
        loop {
            let message = match self.write_rx.poll()? {
                Async::NotReady => return Ok(Async::NotReady),
                Async::Ready(Some(message)) => message,
                Async::Ready(None) => return Ok(Async::Ready(())), // Add some diagnostics maybe?
            };

            self.process_message(message)?;
        }
    }

    fn poll_flush(&mut self) -> result::Result<()> {
        self.buffer_outg_conn()?;
        loop {
            self.queued_write.poll()?;
            let updated = self.buffer_outg_conn()?;
            if !updated {
                return Ok(());
            }
        }
    }

    pub fn poll_write(&mut self) -> Poll<(), error::Error> {
        if let Async::Ready(()) = self.process_write_queue()? {
            return Ok(Async::Ready(()));
        }

        self.poll_flush()?;

        Ok(Async::NotReady)
    }
}

// Message sent to write loop.
// Processed while write loop is not handling network I/O.
pub enum CommonToWriteMessage {
    IncreaseInWindow(StreamId, u32),
    StreamEnqueue(StreamId, DataOrHeadersWithFlag),
    StreamEnd(StreamId, ErrorCode), // send when user provided handler completed the stream
    DumpState(oneshot::Sender<ConnStateSnapshot>),
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::gc::{Gc, GC};
use syntax::{ast, ast_util, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::{attr, codemap};
use syntax::parse::token;

enum ParamType {
    ParamUniform,
    ParamBlock,
    ParamTexture,
}

#[deriving(Show)]
enum ParamError {
    ErrorDeprecatedTexture,
    ErrorUnknown,
}

/// Classify variable types (`i32`, `TextureParam`, etc) into the `ParamType`
fn classify(node: &ast::Ty_) -> Result<ParamType, ParamError> {
    match *node {
        ast::TyPath(ref path, _, _) => match path.segments.last() {
            Some(segment) => match segment.identifier.name.as_str() {
                "BufferHandle" => Ok(ParamBlock),
                "TextureParam" => Ok(ParamTexture),
                "TextureHandle" => Err(ErrorDeprecatedTexture),
                _ => Ok(ParamUniform),
            },
            None => Ok(ParamUniform),
        },
        _ => Ok(ParamUniform),
    }
}

/// Scan through the field's attributes and find out if it needs to be linked
/// with the shader.
/// #[unused] attribute prevents that
fn is_field_used(field: &ast::StructField) -> bool {
    field.node.attrs.iter().find(|attribute| {
        match attribute.node.value.node {
            ast::MetaWord(ref word) if word.get() == "unused" => {
                attr::mark_used(*attribute);
                true
            },
            _ => false,
        }
    }).is_none()
}

/// Generates the the method body for `gfx::shade::ParamValues::create_link`
fn method_create(cx: &mut ext::base::ExtCtxt, span: codemap::Span, substr: &generic::Substructure,
                 definition: Gc<ast::StructDef>, link_name: &str) -> Gc<ast::Expr> {
    let link_ident = cx.ident_of(link_name);
    match *substr.fields {
        //generic::StaticStruct(definition, generic::Named(ref fields)) => {
        generic::Struct(ref fields) => {
            let out = definition.fields.iter().zip(fields.iter())
                .filter(|&(def, _)| is_field_used(def)).map(|(def, f)| {
                let name = cx.expr_str(span, token::get_ident(f.name.unwrap()));
                let input = substr.nonself_args[0];
                let expr = match classify(&def.node.ty.node) {
                    //TODO: verify the type match
                    Ok(ParamUniform) => super::ugh(cx, |cx| quote_expr!(cx,
                        match $input.val0().iter().position(|u| u.name.as_slice() == $name) {
                            Some(p) => p as gfx::shade::VarUniform,
                            None => return Err(gfx::shade::ErrorUniform($name)),
                        }
                    )),
                    Ok(ParamBlock)   => super::ugh(cx, |cx| quote_expr!(cx,
                        match $input.val1().iter().position(|b| b.name.as_slice() == $name) {
                            Some(p) => p as gfx::shade::VarBlock,
                            None => return Err(gfx::shade::ErrorBlock($name)),
                        }
                    )),
                    Ok(ParamTexture) => super::ugh(cx, |cx| quote_expr!(cx,
                        match $input.val2().iter().position(|t| t.name.as_slice() == $name) {
                            Some(p) => p as gfx::shade::VarTexture,
                            None => return Err(gfx::shade::ErrorTexture($name)),
                        }
                    )),
                    Err(_) => {
                        cx.span_err(span, format!(
                            "Invalid uniform: {}",
                            f.name.unwrap().as_str(),
                            ).as_slice()
                        );
                        return cx.field_imm(span,
                            cx.ident_of("invalid"),
                            cx.expr_uint(span, 0)
                            );
                    },
                };
                cx.field_imm(f.span, f.name.unwrap(), expr)
            }).collect();
            cx.expr_ok(span, cx.expr_struct_ident(span, link_ident, out))
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::create_link()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        },
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::fill_params`
fn method_fill(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               substr: &generic::Substructure, definition: Gc<ast::StructDef>)
               -> Gc<ast::Expr> {
    match *substr.fields {
        generic::Struct(ref fields) => {
            let calls = definition.fields.iter().zip(fields.iter())
            .filter(|&(def, _)| is_field_used(def)).map(|(def, f)| {
                let out = substr.nonself_args[1];
                let value_id = f.self_;
                let var_id = cx.expr_field_access(
                    span,
                    substr.nonself_args[0],
                    f.name.unwrap()
                    );
                match classify(&def.node.ty.node) {
                    Ok(ParamUniform) => super::ugh(cx, |cx| quote_stmt!(cx,
                        $out.uniforms[$var_id as uint] = Some($value_id.to_uniform());
                    )),
                    Ok(ParamBlock)   => super::ugh(cx, |cx| quote_stmt!(cx,
                        $out.blocks[$var_id as uint] = Some $value_id;
                    )),
                    Ok(ParamTexture) => super::ugh(cx, |cx| quote_stmt!(cx,
                        $out.textures[$var_id as uint] = Some $value_id;
                    )),
                    Err(_) => {
                        cx.span_err(span, format!(
                            "Invalid uniform: {}",
                            f.name.unwrap().as_str(),
                            ).as_slice()
                        );
                        cx.stmt_expr(cx.expr_uint(span, 0))
                    },
                }
            }).collect();
            let view = cx.view_use_simple(
                span,
                ast::Inherited,
                cx.path(span, vec![
                    cx.ident_of("gfx"),
                    cx.ident_of("shade"),
                    cx.ident_of("ToUniform"),
                ])
            );
            cx.expr_block(cx.block_all(span, vec![view], calls, None))
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::bind()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// A helper function that translates variable type (`i32`, `TextureHandle`, etc)
/// into the corresponding shader var id type (`VarUniform`, `VarBlock`, or `VarTexture`)
fn node_to_var_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span, node: &ast::Ty_) -> Gc<ast::Ty> {
    let id = match classify(node) {
        Ok(ParamUniform) => "VarUniform",
        Ok(ParamBlock)   => "VarBlock",
        Ok(ParamTexture) => "VarTexture",
        Err(ErrorDeprecatedTexture) => {
            cx.span_err(span, "Use gfx::shade::TextureParam for texture vars instead of gfx::shade::TextureHandle");
            ""
        },
        Err(ErrorUnknown) => {
            cx.span_err(span, format!("Unknown node: {}", node).as_slice());
            ""
        },
    };
    cx.ty_path(cx.path_global(span, vec![
        cx.ident_of("gfx"),
        cx.ident_of("shade"),
        cx.ident_of(id),
    ]), None)
}

/// Decorator for `shader_param` attribute
pub fn expand(context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: Gc<ast::MetaItem>, item: Gc<ast::Item>,
              push: |Gc<ast::Item>|) {
    // constructing the Link struct
    let (base_def, link_def) = match item.node {
        ast::ItemStruct(definition, ref generics) => {
            if generics.lifetimes.len() > 0 {
                context.bug("Generics are not allowed in ShaderParam struct");
            }
            (definition, ast::StructDef {
                fields: definition.fields.iter()
                    .filter(|&f| is_field_used(f))
                    .map(|f| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: f.node.kind,
                            id: f.node.id,
                            ty: node_to_var_type(context, f.span, &f.node.ty.node),
                            attrs: Vec::new(),
                        },
                        span: f.span,
                    }).collect(),
                ctor_id: None,
                super_struct: None,
                is_virtual: false,
            })
        },
        _ => {
            context.span_err(span, "Only free-standing named structs allowed to derive ShaderParam");
            return;
        }
    };
    let link_name = format!("_{}Link", item.ident.as_str());
    let link_ident = context.ident_of(link_name.as_slice());
    let link_ty = box generic::ty::Literal(
        generic::ty::Path::new_local(link_name.as_slice())
    );
    // Almost `context.item_struct(span, link_ident, link_def)` but with visibility
    push(box (GC) ast::Item {
        ident: link_ident,
        attrs: Vec::new(),
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemStruct(
            box(GC) link_def,
            ast_util::empty_generics()
        ),
        vis: item.vis,
        span: span,
    });
    // constructing the `CustomShell` typedef
    match meta_item.node {
        ast::MetaWord(_) => (),
        ast::MetaList(_, ref items) if items.len() == 1 => match items[0].deref().node {
            ast::MetaWord(ref shell_name) => {
                // pub type $shell_ident = gfx::shade::CustomShell<$link_ident, $self_ident>
                let path = context.ty_path(
                    context.path_all(span, true,
                        vec![
                            context.ident_of("gfx"),
                            context.ident_of("shade"),
                            context.ident_of("CustomShell"),
                        ],
                        Vec::new(),
                        vec![
                            context.ty_ident(span, link_ident),
                            context.ty_ident(span, item.ident)
                        ]
                    ), None
                );
                push(box(GC) ast::Item {
                    ident: context.ident_of(shell_name.get()),
                    attrs: Vec::new(),
                    id: ast::DUMMY_NODE_ID,
                    node: ast::ItemTy(path, ast_util::empty_generics()),
                    vis: item.vis,
                    span: span,
                })
            },
            _ => {
                context.span_err(meta_item.span,
                    "Invalid arguments for `#[shader_param]`")
            }
        },
        _ => {
            context.span_err(meta_item.span,
                "Invalid arguments for `#[shader_param]`")
        }
    }
    // deriving ShaderParam
    let trait_def = generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec!["gfx", "shade", "ShaderParam"],
            lifetime: None,
            params: vec![link_ty.clone()],
            global: true,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            generic::MethodDef {
                name: "create_link",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: Some(Some(generic::ty::Borrowed(
                    None, ast::MutImmutable
                ))),
                args: vec![
                    generic::ty::Literal(generic::ty::Path::new(
                        vec!["gfx", "shade", "ParamLinkInput"])),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Result"],
                        lifetime: None,
                        params: vec![
                            link_ty.clone(),
                            box generic::ty::Literal(generic::ty::Path {
                                path: vec!["gfx", "shade", "ParameterError"],
                                lifetime: Some("'static"),
                                params: Vec::new(),
                                global: true,
                            })
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_create(cx, span, sub, base_def, link_name.as_slice())
                ),
            },
            generic::MethodDef {
                name: "fill_params",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: Some(Some(generic::ty::Borrowed(
                    None, ast::MutImmutable
                ))),
                args: vec![
                    generic::ty::Ptr(
                        link_ty.clone(),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                    generic::ty::Literal(
                        generic::ty::Path::new(vec!["gfx", "shade", "ParamValues"]),
                    ),
                ],
                ret_ty: generic::ty::Tuple(Vec::new()),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_fill(cx, span, sub, base_def)
                ),
            },
        ],
    };
    trait_def.expand(context, meta_item, item, push);
}
<commit_msg>Copying deriving attributes for the parameter link<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::gc::{Gc, GC};
use syntax::{ast, ast_util, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::{attr, codemap};
use syntax::parse::token;

enum ParamType {
    ParamUniform,
    ParamBlock,
    ParamTexture,
}

#[deriving(Show)]
enum ParamError {
    ErrorDeprecatedTexture,
    ErrorUnknown,
}

/// Classify variable types (`i32`, `TextureParam`, etc) into the `ParamType`
fn classify(node: &ast::Ty_) -> Result<ParamType, ParamError> {
    match *node {
        ast::TyPath(ref path, _, _) => match path.segments.last() {
            Some(segment) => match segment.identifier.name.as_str() {
                "BufferHandle" => Ok(ParamBlock),
                "TextureParam" => Ok(ParamTexture),
                "TextureHandle" => Err(ErrorDeprecatedTexture),
                _ => Ok(ParamUniform),
            },
            None => Ok(ParamUniform),
        },
        _ => Ok(ParamUniform),
    }
}

/// Scan through the field's attributes and find out if it needs to be linked
/// with the shader.
/// #[unused] attribute prevents that
fn is_field_used(field: &ast::StructField) -> bool {
    field.node.attrs.iter().find(|attribute| {
        match attribute.node.value.node {
            ast::MetaWord(ref word) if word.get() == "unused" => {
                attr::mark_used(*attribute);
                true
            },
            _ => false,
        }
    }).is_none()
}

/// Generates the the method body for `gfx::shade::ParamValues::create_link`
fn method_create(cx: &mut ext::base::ExtCtxt, span: codemap::Span, substr: &generic::Substructure,
                 definition: Gc<ast::StructDef>, link_name: &str) -> Gc<ast::Expr> {
    let link_ident = cx.ident_of(link_name);
    match *substr.fields {
        //generic::StaticStruct(definition, generic::Named(ref fields)) => {
        generic::Struct(ref fields) => {
            let out = definition.fields.iter().zip(fields.iter())
                .filter(|&(def, _)| is_field_used(def)).map(|(def, f)| {
                let name = cx.expr_str(span, token::get_ident(f.name.unwrap()));
                let input = substr.nonself_args[0];
                let expr = match classify(&def.node.ty.node) {
                    //TODO: verify the type match
                    Ok(ParamUniform) => super::ugh(cx, |cx| quote_expr!(cx,
                        match $input.val0().iter().position(|u| u.name.as_slice() == $name) {
                            Some(p) => p as gfx::shade::VarUniform,
                            None => return Err(gfx::shade::ErrorUniform($name)),
                        }
                    )),
                    Ok(ParamBlock)   => super::ugh(cx, |cx| quote_expr!(cx,
                        match $input.val1().iter().position(|b| b.name.as_slice() == $name) {
                            Some(p) => p as gfx::shade::VarBlock,
                            None => return Err(gfx::shade::ErrorBlock($name)),
                        }
                    )),
                    Ok(ParamTexture) => super::ugh(cx, |cx| quote_expr!(cx,
                        match $input.val2().iter().position(|t| t.name.as_slice() == $name) {
                            Some(p) => p as gfx::shade::VarTexture,
                            None => return Err(gfx::shade::ErrorTexture($name)),
                        }
                    )),
                    Err(_) => {
                        cx.span_err(span, format!(
                            "Invalid uniform: {}",
                            f.name.unwrap().as_str(),
                            ).as_slice()
                        );
                        return cx.field_imm(span,
                            cx.ident_of("invalid"),
                            cx.expr_uint(span, 0)
                            );
                    },
                };
                cx.field_imm(f.span, f.name.unwrap(), expr)
            }).collect();
            cx.expr_ok(span, cx.expr_struct_ident(span, link_ident, out))
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::create_link()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        },
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::fill_params`
fn method_fill(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               substr: &generic::Substructure, definition: Gc<ast::StructDef>)
               -> Gc<ast::Expr> {
    match *substr.fields {
        generic::Struct(ref fields) => {
            let calls = definition.fields.iter().zip(fields.iter())
            .filter(|&(def, _)| is_field_used(def)).map(|(def, f)| {
                let out = substr.nonself_args[1];
                let value_id = f.self_;
                let var_id = cx.expr_field_access(
                    span,
                    substr.nonself_args[0],
                    f.name.unwrap()
                    );
                match classify(&def.node.ty.node) {
                    Ok(ParamUniform) => super::ugh(cx, |cx| quote_stmt!(cx,
                        $out.uniforms[$var_id as uint] = Some($value_id.to_uniform());
                    )),
                    Ok(ParamBlock)   => super::ugh(cx, |cx| quote_stmt!(cx,
                        $out.blocks[$var_id as uint] = Some $value_id;
                    )),
                    Ok(ParamTexture) => super::ugh(cx, |cx| quote_stmt!(cx,
                        $out.textures[$var_id as uint] = Some $value_id;
                    )),
                    Err(_) => {
                        cx.span_err(span, format!(
                            "Invalid uniform: {}",
                            f.name.unwrap().as_str(),
                            ).as_slice()
                        );
                        cx.stmt_expr(cx.expr_uint(span, 0))
                    },
                }
            }).collect();
            let view = cx.view_use_simple(
                span,
                ast::Inherited,
                cx.path(span, vec![
                    cx.ident_of("gfx"),
                    cx.ident_of("shade"),
                    cx.ident_of("ToUniform"),
                ])
            );
            cx.expr_block(cx.block_all(span, vec![view], calls, None))
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::bind()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// A helper function that translates variable type (`i32`, `TextureHandle`, etc)
/// into the corresponding shader var id type (`VarUniform`, `VarBlock`, or `VarTexture`)
fn node_to_var_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span, node: &ast::Ty_) -> Gc<ast::Ty> {
    let id = match classify(node) {
        Ok(ParamUniform) => "VarUniform",
        Ok(ParamBlock)   => "VarBlock",
        Ok(ParamTexture) => "VarTexture",
        Err(ErrorDeprecatedTexture) => {
            cx.span_err(span, "Use gfx::shade::TextureParam for texture vars instead of gfx::shade::TextureHandle");
            ""
        },
        Err(ErrorUnknown) => {
            cx.span_err(span, format!("Unknown node: {}", node).as_slice());
            ""
        },
    };
    cx.ty_path(cx.path_global(span, vec![
        cx.ident_of("gfx"),
        cx.ident_of("shade"),
        cx.ident_of(id),
    ]), None)
}

/// Extract all deriving() attributes into a separate array
fn copy_deriving(attribs: &[ast::Attribute]) -> Vec<ast::Attribute> {
    attribs.iter().filter(|at| {
        match at.node.value.node {
            ast::MetaList(ref s, _) => s.get() == "deriving",
            _ => false,
        }
    }).map(|at| *at).collect()
}

/// Decorator for `shader_param` attribute
pub fn expand(context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: Gc<ast::MetaItem>, item: Gc<ast::Item>,
              push: |Gc<ast::Item>|) {
    // constructing the Link struct
    let (base_def, link_def) = match item.node {
        ast::ItemStruct(definition, ref generics) => {
            if generics.lifetimes.len() > 0 {
                context.bug("Generics are not allowed in ShaderParam struct");
            }
            (definition, ast::StructDef {
                fields: definition.fields.iter()
                    .filter(|&f| is_field_used(f))
                    .map(|f| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: f.node.kind,
                            id: f.node.id,
                            ty: node_to_var_type(context, f.span, &f.node.ty.node),
                            attrs: Vec::new(),
                        },
                        span: f.span,
                    }).collect(),
                ctor_id: None,
                super_struct: None,
                is_virtual: false,
            })
        },
        _ => {
            context.span_err(span, "Only free-standing named structs allowed to derive ShaderParam");
            return;
        }
    };
    let link_name = format!("_{}Link", item.ident.as_str());
    let link_ident = context.ident_of(link_name.as_slice());
    let link_ty = box generic::ty::Literal(
        generic::ty::Path::new_local(link_name.as_slice())
    );
    // Almost `context.item_struct(span, link_ident, link_def)` but with visibility
    push(box (GC) ast::Item {
        ident: link_ident,
        attrs: copy_deriving(item.attrs.as_slice()),
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemStruct(
            box(GC) link_def,
            ast_util::empty_generics()
        ),
        vis: item.vis,
        span: span,
    });
    // constructing the `CustomShell` typedef
    match meta_item.node {
        ast::MetaWord(_) => (),
        ast::MetaList(_, ref items) if items.len() == 1 => match items[0].deref().node {
            ast::MetaWord(ref shell_name) => {
                // pub type $shell_ident = gfx::shade::CustomShell<$link_ident, $self_ident>
                let path = context.ty_path(
                    context.path_all(span, true,
                        vec![
                            context.ident_of("gfx"),
                            context.ident_of("shade"),
                            context.ident_of("CustomShell"),
                        ],
                        Vec::new(),
                        vec![
                            context.ty_ident(span, link_ident),
                            context.ty_ident(span, item.ident)
                        ]
                    ), None
                );
                push(box(GC) ast::Item {
                    ident: context.ident_of(shell_name.get()),
                    attrs: Vec::new(),
                    id: ast::DUMMY_NODE_ID,
                    node: ast::ItemTy(path, ast_util::empty_generics()),
                    vis: item.vis,
                    span: span,
                })
            },
            _ => {
                context.span_err(meta_item.span,
                    "Invalid arguments for `#[shader_param]`")
            }
        },
        _ => {
            context.span_err(meta_item.span,
                "Invalid arguments for `#[shader_param]`")
        }
    }
    // deriving ShaderParam
    let trait_def = generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec!["gfx", "shade", "ShaderParam"],
            lifetime: None,
            params: vec![link_ty.clone()],
            global: true,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            generic::MethodDef {
                name: "create_link",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: Some(Some(generic::ty::Borrowed(
                    None, ast::MutImmutable
                ))),
                args: vec![
                    generic::ty::Literal(generic::ty::Path::new(
                        vec!["gfx", "shade", "ParamLinkInput"])),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Result"],
                        lifetime: None,
                        params: vec![
                            link_ty.clone(),
                            box generic::ty::Literal(generic::ty::Path {
                                path: vec!["gfx", "shade", "ParameterError"],
                                lifetime: Some("'static"),
                                params: Vec::new(),
                                global: true,
                            })
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_create(cx, span, sub, base_def, link_name.as_slice())
                ),
            },
            generic::MethodDef {
                name: "fill_params",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: Some(Some(generic::ty::Borrowed(
                    None, ast::MutImmutable
                ))),
                args: vec![
                    generic::ty::Ptr(
                        link_ty.clone(),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                    generic::ty::Literal(
                        generic::ty::Path::new(vec!["gfx", "shade", "ParamValues"]),
                    ),
                ],
                ret_ty: generic::ty::Tuple(Vec::new()),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_fill(cx, span, sub, base_def)
                ),
            },
        ],
    };
    trait_def.expand(context, meta_item, item, push);
}
<|endoftext|>


<commit_before>//! Definitions for uclibc on 64bit systems
pub type blkcnt_t = i64;
pub type blksize_t = i64;
pub type clock_t = i64;
pub type c_char = u8;
pub type c_long = i64;
pub type c_ulong = u64;
pub type fsblkcnt_t = ::c_ulong;
pub type fsfilcnt_t = ::c_ulong;
pub type fsword_t = ::c_long;
pub type ino_t = ::c_ulong;
pub type nlink_t = ::c_uint;
pub type off_t = ::c_long;
pub type rlim_t = c_ulong;
// [uClibc docs] Note stat64 has the same shape as stat for x86-64.
pub type stat64 = stat;
pub type suseconds_t = ::c_long;
pub type time_t = ::c_int;
pub type wchar_t = ::c_int;

pub type fsblkcnt64_t = u64;
pub type fsfilcnt64_t = u64;
pub type __u64 = ::c_ulong;

s! {
    pub struct ipc_perm {
        pub __key: ::key_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
        pub cuid: ::uid_t,
        pub cgid: ::gid_t,
        pub mode: ::c_ushort, // read / write
        __pad1: ::c_ushort,
        pub __seq: ::c_ushort,
        __pad2: ::c_ushort,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    #[cfg(not(target_os = "l4re"))]
    pub struct pthread_attr_t {
        __detachstate: ::c_int,
        __schedpolicy: ::c_int,
        __schedparam: __sched_param,
        __inheritsched: ::c_int,
        __scope: ::c_int,
        __guardsize: ::size_t,
        __stackaddr_set: ::c_int,
        __stackaddr: *mut ::c_void, // better don't use it
        __stacksize: ::size_t,
    }

    pub struct __sched_param {
        __sched_priority: ::c_int,
    }

    pub struct siginfo_t {
        si_signo: ::c_int, // signal number
        si_errno: ::c_int, // if not zero: error value of signal, see errno.h
        si_code: ::c_int,  // signal code
        pub _pad: [::c_int; 28], // unported union
        _align: [usize; 0],
    }

    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t, // segment size in bytes
        pub shm_atime: ::time_t, // time of last shmat()
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_cpid: ::pid_t,
        pub shm_lpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    pub struct msqid_ds {
        pub msg_perm: ::ipc_perm,
        pub msg_stime: ::time_t,
        pub msg_rtime: ::time_t,
        pub msg_ctime: ::time_t,
        __msg_cbytes: ::c_ulong,
        pub msg_qnum: ::msgqnum_t,
        pub msg_qbytes: ::msglen_t,
        pub msg_lspid: ::pid_t,
        pub msg_lrpid: ::pid_t,
        __ignored1: ::c_ulong,
        __ignored2: ::c_ulong,
    }

    pub struct sockaddr {
        pub sa_family: ::sa_family_t,
        pub sa_data: [::c_char; 14],
    }

    pub struct sockaddr_in {
        pub sin_family: ::sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
        pub sin_zero: [u8; 8],
    }

    pub struct sockaddr_in6 {
        pub sin6_family: ::sa_family_t,
        pub sin6_port: ::in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }

    // ------------------------------------------------------------
    // definitions below are *unverified* and might **break** the software
//    pub struct in_addr {
//        pub s_addr: in_addr_t,
//    }
//
//    pub struct in6_addr {
//        pub s6_addr: [u8; 16],
//        #[cfg(not(libc_align))]
//        __align: [u32; 0],
//    }

    pub struct stat {
        pub st_dev: ::c_ulong,
        pub st_ino: ::ino_t,
        // According to uclibc/libc/sysdeps/linux/x86_64/bits/stat.h, order of
        // nlink and mode are swapped on 64 bit systems.
        pub st_nlink: ::nlink_t,
        pub st_mode: ::mode_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        pub st_rdev: ::c_ulong, // dev_t
        pub st_size: off_t, // file size
        pub st_blksize: ::blksize_t,
        pub st_blocks: ::blkcnt_t,
        pub st_atime: ::time_t,
        pub st_atime_nsec: ::c_ulong,
        pub st_mtime: ::time_t,
        pub st_mtime_nsec: ::c_ulong,
        pub st_ctime: ::time_t,
        pub st_ctime_nsec: ::c_ulong,
        st_pad4: [::c_long; 3]
    }

    pub struct sigaction {
        pub sa_handler: ::sighandler_t,
        pub sa_flags: ::c_ulong,
        pub sa_restorer: ::Option<extern fn()>,
        pub sa_mask: ::sigset_t,
    }

    pub struct stack_t { // FIXME
        pub ss_sp: *mut ::c_void,
        pub ss_flags: ::c_int,
        pub ss_size: ::size_t
    }

    pub struct statfs { // FIXME
        pub f_type: fsword_t,
        pub f_bsize: fsword_t,
        pub f_blocks: ::fsblkcnt_t,
        pub f_bfree: ::fsblkcnt_t,
        pub f_bavail: ::fsblkcnt_t,
        pub f_files: ::fsfilcnt_t,
        pub f_ffree: ::fsfilcnt_t,
        pub f_fsid: ::fsid_t,
        pub f_namelen: fsword_t,
        pub f_frsize: fsword_t,
        f_spare: [fsword_t; 5],
    }

    pub struct statfs64 {
        pub f_type: ::c_int,
        pub f_bsize: ::c_int,
        pub f_blocks: ::fsblkcnt64_t,
        pub f_bfree: ::fsblkcnt64_t,
        pub f_bavail: ::fsblkcnt64_t,
        pub f_files: ::fsfilcnt64_t,
        pub f_ffree: ::fsfilcnt64_t,
        pub f_fsid: ::fsid_t,
        pub f_namelen: ::c_int,
        pub f_frsize: ::c_int,
        pub f_flags: ::c_int,
        pub f_spare: [::c_int; 4],
    }

    pub struct statvfs64 {
        pub f_bsize: ::c_ulong,
        pub f_frsize: ::c_ulong,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: u64,
        pub f_files: u64,
        pub f_ffree: u64,
        pub f_favail: u64,
        pub f_fsid: ::c_ulong,
        __f_unused: ::c_int,
        pub f_flag: ::c_ulong,
        pub f_namemax: ::c_ulong,
        __f_spare: [::c_int; 6],
    }

    pub struct msghdr { // FIXME
        pub msg_name: *mut ::c_void,
        pub msg_namelen: ::socklen_t,
        pub msg_iov: *mut ::iovec,
        pub msg_iovlen: ::size_t,
        pub msg_control: *mut ::c_void,
        pub msg_controllen: ::size_t,
        pub msg_flags: ::c_int,
    }

    pub struct termios { // FIXME
        pub c_iflag: ::tcflag_t,
        pub c_oflag: ::tcflag_t,
        pub c_cflag: ::tcflag_t,
        pub c_lflag: ::tcflag_t,
        pub c_line: ::cc_t,
        pub c_cc: [::cc_t; ::NCCS],
    }

    pub struct sigset_t { // FIXME
        __val: [::c_ulong; 16],
    }

    pub struct sysinfo { // FIXME
        pub uptime: ::c_long,
        pub loads: [::c_ulong; 3],
        pub totalram: ::c_ulong,
        pub freeram: ::c_ulong,
        pub sharedram: ::c_ulong,
        pub bufferram: ::c_ulong,
        pub totalswap: ::c_ulong,
        pub freeswap: ::c_ulong,
        pub procs: ::c_ushort,
        pub pad: ::c_ushort,
        pub totalhigh: ::c_ulong,
        pub freehigh: ::c_ulong,
        pub mem_unit: ::c_uint,
        pub _f: [::c_char; 0],
    }

    pub struct glob_t { // FIXME
        pub gl_pathc: ::size_t,
        pub gl_pathv: *mut *mut c_char,
        pub gl_offs: ::size_t,
        pub gl_flags: ::c_int,
        __unused1: *mut ::c_void,
        __unused2: *mut ::c_void,
        __unused3: *mut ::c_void,
        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
    }

    pub struct cpu_set_t { // FIXME
        #[cfg(target_pointer_width = "32")]
        bits: [u32; 32],
        #[cfg(target_pointer_width = "64")]
        bits: [u64; 16],
    }

    pub struct fsid_t { // FIXME
        __val: [::c_int; 2],
    }

    // FIXME this is actually a union
    pub struct sem_t {
        #[cfg(target_pointer_width = "32")]
        __size: [::c_char; 16],
        #[cfg(target_pointer_width = "64")]
        __size: [::c_char; 32],
        __align: [::c_long; 0],
    }

    pub struct cmsghdr {
        pub cmsg_len: ::size_t,
        pub cmsg_level: ::c_int,
        pub cmsg_type: ::c_int,
    }
}

s_no_extra_traits! {
    #[allow(missing_debug_implementations)]
    pub struct dirent {
        pub d_ino: ::ino64_t,
        pub d_off: ::off64_t,
        pub d_reclen: u16,
        pub d_type: u8,
        pub d_name: [::c_char; 256],
    }
}

// constants
pub const EADDRINUSE: ::c_int = 98; // Address already in use
pub const EADDRNOTAVAIL: ::c_int = 99; // Cannot assign requested address
pub const ECONNABORTED: ::c_int = 103; // Software caused connection abort
pub const ECONNREFUSED: ::c_int = 111; // Connection refused
pub const ECONNRESET: ::c_int = 104; // Connection reset by peer
pub const EDEADLK: ::c_int = 35; // Resource deadlock would occur
pub const ENOSYS: ::c_int = 38; // Function not implemented
pub const ENOTCONN: ::c_int = 107; // Transport endpoint is not connected
pub const ETIMEDOUT: ::c_int = 110; // connection timed out
pub const EOPNOTSUPP: ::c_int = 0x5f;
pub const ENODATA: ::c_int = 0x3d;
pub const O_APPEND: ::c_int = 02000;
pub const O_ACCMODE: ::c_int = 0003;
pub const O_CLOEXEC: ::c_int = 0x80000;
pub const O_CREAT: ::c_int = 0100;
pub const O_DIRECTORY: ::c_int = 0200000;
pub const O_EXCL: ::c_int = 0200;
pub const O_NONBLOCK: ::c_int = 04000;
pub const O_TRUNC: ::c_int = 01000;
pub const NCCS: usize = 32;
pub const SIG_SETMASK: ::c_int = 2; // Set the set of blocked signals
pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40;
pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4;
pub const SOCK_DGRAM: ::c_int = 2; // connectionless, unreliable datagrams
pub const SOCK_STREAM: ::c_int = 1; // …/common/bits/socket_type.h
pub const RLIM_INFINITY: u64 = 0xffffffffffffffff;
pub const __SIZEOF_PTHREAD_COND_T: usize = 48;
pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4;
pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56;
pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8;

cfg_if! {
    if #[cfg(target_os = "l4re")] {
        mod l4re;
        pub use self::l4re::*;
    } else {
        mod other;
        pub use other::*;
    }
}
<commit_msg>Auto merge of #2466 - atopia:master, r=JohnTitor<commit_after>//! Definitions for uclibc on 64bit systems
pub type blkcnt_t = i64;
pub type blksize_t = i64;
pub type clock_t = i64;
pub type c_char = u8;
pub type c_long = i64;
pub type c_ulong = u64;
pub type fsblkcnt_t = ::c_ulong;
pub type fsfilcnt_t = ::c_ulong;
pub type fsword_t = ::c_long;
pub type ino_t = ::c_ulong;
pub type nlink_t = ::c_uint;
pub type off_t = ::c_long;
pub type rlim_t = c_ulong;
// [uClibc docs] Note stat64 has the same shape as stat for x86-64.
pub type stat64 = stat;
pub type suseconds_t = ::c_long;
pub type time_t = ::c_int;
pub type wchar_t = ::c_int;

pub type fsblkcnt64_t = u64;
pub type fsfilcnt64_t = u64;
pub type __u64 = ::c_ulong;

s! {
    pub struct ipc_perm {
        pub __key: ::key_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
        pub cuid: ::uid_t,
        pub cgid: ::gid_t,
        pub mode: ::c_ushort, // read / write
        __pad1: ::c_ushort,
        pub __seq: ::c_ushort,
        __pad2: ::c_ushort,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    #[cfg(not(target_os = "l4re"))]
    pub struct pthread_attr_t {
        __detachstate: ::c_int,
        __schedpolicy: ::c_int,
        __schedparam: __sched_param,
        __inheritsched: ::c_int,
        __scope: ::c_int,
        __guardsize: ::size_t,
        __stackaddr_set: ::c_int,
        __stackaddr: *mut ::c_void, // better don't use it
        __stacksize: ::size_t,
    }

    pub struct __sched_param {
        __sched_priority: ::c_int,
    }

    pub struct siginfo_t {
        si_signo: ::c_int, // signal number
        si_errno: ::c_int, // if not zero: error value of signal, see errno.h
        si_code: ::c_int,  // signal code
        pub _pad: [::c_int; 28], // unported union
        _align: [usize; 0],
    }

    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t, // segment size in bytes
        pub shm_atime: ::time_t, // time of last shmat()
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_cpid: ::pid_t,
        pub shm_lpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    pub struct msqid_ds {
        pub msg_perm: ::ipc_perm,
        pub msg_stime: ::time_t,
        pub msg_rtime: ::time_t,
        pub msg_ctime: ::time_t,
        __msg_cbytes: ::c_ulong,
        pub msg_qnum: ::msgqnum_t,
        pub msg_qbytes: ::msglen_t,
        pub msg_lspid: ::pid_t,
        pub msg_lrpid: ::pid_t,
        __ignored1: ::c_ulong,
        __ignored2: ::c_ulong,
    }

    pub struct sockaddr {
        pub sa_family: ::sa_family_t,
        pub sa_data: [::c_char; 14],
    }

    pub struct sockaddr_in {
        pub sin_family: ::sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
        pub sin_zero: [u8; 8],
    }

    pub struct sockaddr_in6 {
        pub sin6_family: ::sa_family_t,
        pub sin6_port: ::in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }

    // ------------------------------------------------------------
    // definitions below are *unverified* and might **break** the software
//    pub struct in_addr {
//        pub s_addr: in_addr_t,
//    }
//
//    pub struct in6_addr {
//        pub s6_addr: [u8; 16],
//        #[cfg(not(libc_align))]
//        __align: [u32; 0],
//    }

    pub struct stat {
        pub st_dev: ::c_ulong,
        pub st_ino: ::ino_t,
        // According to uclibc/libc/sysdeps/linux/x86_64/bits/stat.h, order of
        // nlink and mode are swapped on 64 bit systems.
        pub st_nlink: ::nlink_t,
        pub st_mode: ::mode_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        pub st_rdev: ::c_ulong, // dev_t
        pub st_size: off_t, // file size
        pub st_blksize: ::blksize_t,
        pub st_blocks: ::blkcnt_t,
        pub st_atime: ::time_t,
        pub st_atime_nsec: ::c_ulong,
        pub st_mtime: ::time_t,
        pub st_mtime_nsec: ::c_ulong,
        pub st_ctime: ::time_t,
        pub st_ctime_nsec: ::c_ulong,
        st_pad4: [::c_long; 3]
    }

    pub struct sigaction {
        pub sa_handler: ::sighandler_t,
        pub sa_flags: ::c_ulong,
        pub sa_restorer: ::Option<extern fn()>,
        pub sa_mask: ::sigset_t,
    }

    pub struct stack_t { // FIXME
        pub ss_sp: *mut ::c_void,
        pub ss_flags: ::c_int,
        pub ss_size: ::size_t
    }

    pub struct statfs { // FIXME
        pub f_type: fsword_t,
        pub f_bsize: fsword_t,
        pub f_blocks: ::fsblkcnt_t,
        pub f_bfree: ::fsblkcnt_t,
        pub f_bavail: ::fsblkcnt_t,
        pub f_files: ::fsfilcnt_t,
        pub f_ffree: ::fsfilcnt_t,
        pub f_fsid: ::fsid_t,
        pub f_namelen: fsword_t,
        pub f_frsize: fsword_t,
        f_spare: [fsword_t; 5],
    }

    pub struct statfs64 {
        pub f_type: ::c_int,
        pub f_bsize: ::c_int,
        pub f_blocks: ::fsblkcnt64_t,
        pub f_bfree: ::fsblkcnt64_t,
        pub f_bavail: ::fsblkcnt64_t,
        pub f_files: ::fsfilcnt64_t,
        pub f_ffree: ::fsfilcnt64_t,
        pub f_fsid: ::fsid_t,
        pub f_namelen: ::c_int,
        pub f_frsize: ::c_int,
        pub f_flags: ::c_int,
        pub f_spare: [::c_int; 4],
    }

    pub struct statvfs64 {
        pub f_bsize: ::c_ulong,
        pub f_frsize: ::c_ulong,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: u64,
        pub f_files: u64,
        pub f_ffree: u64,
        pub f_favail: u64,
        pub f_fsid: ::c_ulong,
        __f_unused: ::c_int,
        pub f_flag: ::c_ulong,
        pub f_namemax: ::c_ulong,
        __f_spare: [::c_int; 6],
    }

    pub struct msghdr { // FIXME
        pub msg_name: *mut ::c_void,
        pub msg_namelen: ::socklen_t,
        pub msg_iov: *mut ::iovec,
        pub msg_iovlen: ::size_t,
        pub msg_control: *mut ::c_void,
        pub msg_controllen: ::size_t,
        pub msg_flags: ::c_int,
    }

    pub struct termios { // FIXME
        pub c_iflag: ::tcflag_t,
        pub c_oflag: ::tcflag_t,
        pub c_cflag: ::tcflag_t,
        pub c_lflag: ::tcflag_t,
        pub c_line: ::cc_t,
        pub c_cc: [::cc_t; ::NCCS],
    }

    pub struct sigset_t { // FIXME
        __val: [::c_ulong; 16],
    }

    pub struct sysinfo { // FIXME
        pub uptime: ::c_long,
        pub loads: [::c_ulong; 3],
        pub totalram: ::c_ulong,
        pub freeram: ::c_ulong,
        pub sharedram: ::c_ulong,
        pub bufferram: ::c_ulong,
        pub totalswap: ::c_ulong,
        pub freeswap: ::c_ulong,
        pub procs: ::c_ushort,
        pub pad: ::c_ushort,
        pub totalhigh: ::c_ulong,
        pub freehigh: ::c_ulong,
        pub mem_unit: ::c_uint,
        pub _f: [::c_char; 0],
    }

    pub struct glob_t { // FIXME
        pub gl_pathc: ::size_t,
        pub gl_pathv: *mut *mut c_char,
        pub gl_offs: ::size_t,
        pub gl_flags: ::c_int,
        __unused1: *mut ::c_void,
        __unused2: *mut ::c_void,
        __unused3: *mut ::c_void,
        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
    }

    pub struct cpu_set_t { // FIXME
        #[cfg(target_pointer_width = "32")]
        bits: [u32; 32],
        #[cfg(target_pointer_width = "64")]
        bits: [u64; 16],
    }

    pub struct fsid_t { // FIXME
        __val: [::c_int; 2],
    }

    // FIXME this is actually a union
    pub struct sem_t {
        #[cfg(target_pointer_width = "32")]
        __size: [::c_char; 16],
        #[cfg(target_pointer_width = "64")]
        __size: [::c_char; 32],
        __align: [::c_long; 0],
    }

    pub struct cmsghdr {
        pub cmsg_len: ::size_t,
        pub cmsg_level: ::c_int,
        pub cmsg_type: ::c_int,
    }
}

s_no_extra_traits! {
    #[allow(missing_debug_implementations)]
    pub struct dirent {
        pub d_ino: ::ino64_t,
        pub d_off: ::off64_t,
        pub d_reclen: u16,
        pub d_type: u8,
        pub d_name: [::c_char; 256],
    }
}

// constants
pub const ENAMETOOLONG: ::c_int = 36; // File name too long
pub const ENOTEMPTY: ::c_int = 39; // Directory not empty
pub const ELOOP: ::c_int = 40; // Too many symbolic links encountered
pub const EADDRINUSE: ::c_int = 98; // Address already in use
pub const EADDRNOTAVAIL: ::c_int = 99; // Cannot assign requested address
pub const ENETDOWN: ::c_int = 100; // Network is down
pub const ENETUNREACH: ::c_int = 101; // Network is unreachable
pub const ECONNABORTED: ::c_int = 103; // Software caused connection abort
pub const ECONNREFUSED: ::c_int = 111; // Connection refused
pub const ECONNRESET: ::c_int = 104; // Connection reset by peer
pub const EDEADLK: ::c_int = 35; // Resource deadlock would occur
pub const ENOSYS: ::c_int = 38; // Function not implemented
pub const ENOTCONN: ::c_int = 107; // Transport endpoint is not connected
pub const ETIMEDOUT: ::c_int = 110; // connection timed out
pub const ESTALE: ::c_int = 116; // Stale file handle
pub const EHOSTUNREACH: ::c_int = 113; // No route to host
pub const EDQUOT: ::c_int = 122; // Quota exceeded
pub const EOPNOTSUPP: ::c_int = 0x5f;
pub const ENODATA: ::c_int = 0x3d;
pub const O_APPEND: ::c_int = 02000;
pub const O_ACCMODE: ::c_int = 0003;
pub const O_CLOEXEC: ::c_int = 0x80000;
pub const O_CREAT: ::c_int = 0100;
pub const O_DIRECTORY: ::c_int = 0200000;
pub const O_EXCL: ::c_int = 0200;
pub const O_NONBLOCK: ::c_int = 04000;
pub const O_TRUNC: ::c_int = 01000;
pub const NCCS: usize = 32;
pub const SIG_SETMASK: ::c_int = 2; // Set the set of blocked signals
pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40;
pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4;
pub const SOCK_DGRAM: ::c_int = 2; // connectionless, unreliable datagrams
pub const SOCK_STREAM: ::c_int = 1; // …/common/bits/socket_type.h
pub const RLIM_INFINITY: u64 = 0xffffffffffffffff;
pub const __SIZEOF_PTHREAD_COND_T: usize = 48;
pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4;
pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56;
pub const __SIZEOF_PTHREAD_RWLOCKATTR_T: usize = 8;

cfg_if! {
    if #[cfg(target_os = "l4re")] {
        mod l4re;
        pub use self::l4re::*;
    } else {
        mod other;
        pub use other::*;
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use angle::Angle;
use point::Point;
use events::{Events, EventKind, Circle};
use beach::{Beach, Arc, ArcStart};
use diagram::{Diagram, Vertex, Face};

struct Builder {
    events: Events,
    beach: Beach,
    diagram: Diagram,
    scan_theta: Angle,
    temporary: Vec<Vertex>,
}

impl Builder {
    fn new(points: &[Point]) -> Result<Self, Error> {
        if points.len() < 2 {
            return Err(Error::FewPoints);
        }
        let mut builder = Builder {
            events: Events::default(),
            beach: Beach::default(),
            diagram: Diagram::default(),
            scan_theta: Angle::from(0.0),
            temporary: Vec::new(),
        };
        for &point in points {
            let face = builder.diagram.add_face(point);
            builder.events.add_site(face, point);
        }
        Ok(builder)
    }

    pub fn build(mut self, relaxations: usize) -> Result<Diagram, Error> {
        self.build_iter();
        for _ in 1..relaxations {
            self.reset();
            self.build_iter();
        }
        self.finish();
        Ok(self.diagram)
    }

    fn build_iter(&mut self) {
        while let Some(event) = self.events.pop() {
            //println!("{:#?}", event);
            let point = event.point;
            self.scan_theta = *point.theta();
            match event.kind {
                EventKind::Site(face) => self.handle_site_event(face, point),
                EventKind::Circle(event) => self.handle_circle_event(event),
            }
        }
    }

    fn reset(&mut self) {
        self.diagram.reset_faces();
        self.diagram.clear_vertices();
        self.diagram.clear_edges();
        for face in self.diagram.faces() {
            self.events.add_site(face, *self.diagram.face_point(face));
        }
        self.temporary.clear();
        self.events.clear();
        self.beach.clear();
        self.scan_theta = Angle::from(0.0);
    }

    fn arc_point(&self, arc: Arc) -> &Point {
        &self.diagram.face_point(self.beach.face(arc))
    }

    fn create_temporary(&mut self, arc0: Arc, arc1: Arc) {
        let index = self.temporary.len();
        self.temporary.push(Vertex::invalid());
        self.beach.set_start(arc0, ArcStart::Temporary(index));
        self.beach.set_start(arc1, ArcStart::Temporary(index));
    }

    fn handle_site_event(&mut self, face: Face, point: Point) {
        if let Some(mut arc) = self.beach.root() {
            if self.beach.len() == 1 {
                self.beach.insert_after(Some(arc), face);
                let arc0 = self.beach.first();
                let arc1 = self.beach.last();
                self.create_temporary(arc0, arc1);
                return;
            }
            let mut use_tree = true;
            loop {
                let prev_arc = self.beach.prev(arc);
                let next_arc = self.beach.next(arc);
                let phi_start = self.arcs_intersection(prev_arc, arc);
                let phi_end = self.arcs_intersection(arc, next_arc);
                match point.phi().is_in_range(phi_start, phi_end) {
                    Ordering::Less => {
                        if use_tree {
                            if let Some(left) = self.beach.left(arc) {
                                arc = left;
                            } else {
                                // the tree has failed us, do the linear search from now on.
                                arc = self.beach.last();
                                use_tree = false;
                            }
                        } else {
                            arc = self.beach.prev(arc);
                        }
                    },
                    Ordering::Greater => {
                        if use_tree {
                            if let Some(right) = self.beach.right(arc) {
                                arc = right;
                            } else {
                                // the tree has failed us, do the linear search from now on.
                                arc = self.beach.first();
                                use_tree = false;
                            }
                        } else {
                            arc = self.beach.next(arc);
                        }
                    },
                    Ordering::Equal => {
                        self.detach_circle(arc);
                        let twin = {
                            let face = self.beach.face(arc);
                            let a = if prev_arc == self.beach.last() {
                                None
                            } else {
                                Some(prev_arc)
                            };
                            self.beach.insert_after(a, face)
                        };
                        let new_arc = self.beach.insert_after(Some(twin), face);
                        self.create_temporary(twin, new_arc);
                        self.attach_circle(prev_arc, twin, new_arc, point.theta().value());
                        self.attach_circle(new_arc, arc, next_arc, point.theta().value());
                        if self.detach_circle(prev_arc) {
                            let prev_prev = self.beach.prev(prev_arc);
                            self.attach_circle(prev_prev, prev_arc, twin, ::std::f64::MIN);
                        }
                        break;
                    }
                }
            }
        } else {
            self.beach.insert_after(None, face);
        }
    }

    fn merge_arcs(&mut self, arc0: Arc, arc1: Arc, arc2: Arc, vertex: Option<Vertex>) {
        let (face0, face1, face2) = (self.beach.face(arc0), self.beach.face(arc1), self.beach.face(arc2));
        if face0 != face1 && face1 != face2 && face2 != face0 {
            let theta = self.scan_theta.value();
            if self.attach_circle(arc0, arc1, arc2, theta) {
                if let Some(vertex) = vertex {
                    self.beach.set_start(arc1, ArcStart::Vertex(vertex));
                }
            }
        }
    }

    fn edge_from_arc(&mut self, arc: Arc, end: Vertex) {
        match self.beach.start(arc) {
            ArcStart::Temporary(index) => {
                let start = self.temporary[index];
                if start.is_invalid() {
                    self.temporary[index] = end;
                } else {
                    self.diagram.add_edge(start, end);
                }
            },
            ArcStart::Vertex(start) => {
                self.diagram.add_edge(start, end);
            },
            ArcStart::None => {},
        };
    }

    fn handle_circle_event(&mut self, event: Circle) {
        if self.events.is_invalid(event) {
            return;
        }
        let arc = self.events.arc(event);
        assert_eq!(self.beach.circle(arc), Some(event));
        let prev = self.beach.prev(arc);
        let next = self.beach.next(arc);
        self.detach_circle(prev);
        self.detach_circle(next);
        let point = self.events.center(event);
        let vertex = self.diagram.add_vertex(point, &[self.beach.face(prev), self.beach.face(arc), self.beach.face(next)]);
        self.edge_from_arc(prev, vertex);
        self.edge_from_arc(arc, vertex);
        self.beach.remove(arc);
        if self.beach.prev(prev) == next {
            self.edge_from_arc(next, vertex);
            self.beach.remove(prev);
            self.beach.remove(next);
        } else {
            let prev_prev = self.beach.prev(prev);
            let next_next = self.beach.next(next);
            self.merge_arcs(prev_prev, prev, next, Some(vertex));
            self.merge_arcs(prev, next, next_next, None);
        }
    }

    fn arcs_intersection(&self, arc0: Arc, arc1: Arc) -> f64 {
        let point0 = self.arc_point(arc0);
        let theta0 = point0.theta();
        let phi0 = point0.phi();
        let point1 = self.arc_point(arc1);
        let theta1 = point1.theta();
        let phi1 = point1.phi();
        let u1 = (self.scan_theta.cos() - theta1.cos()) * theta0.sin();
        let u2 = (self.scan_theta.cos() - theta0.cos()) * theta1.sin();
        let a1 = u1 * phi0.cos();
        let a2 = u2 * phi1.cos();
        let a = a1 - a2;
        let b1 = u1 * phi0.sin();
        let b2 = u2 * phi1.sin();
        let b = b1 - b2;
        let c = (theta0.cos() - theta1.cos()) * self.scan_theta.sin();
        let length = (a * a + b * b).sqrt();
        if a.abs() > length || c.abs() > length {
            unreachable!()
        } else {
            let gamma = a.atan2(b);
            let phi_int_plus_gamma1 = (c / length).asin();
            Angle::wrap(phi_int_plus_gamma1 - gamma)
        }
    }

    fn attach_circle(&mut self, arc0: Arc, arc1: Arc, arc2: Arc, min_theta: f64) -> bool {
        let p1 = self.arc_point(arc1).position();
        let p01 = self.arc_point(arc0).position() - p1;
        let p21 = self.arc_point(arc2).position() - p1;
        let cross = p01.cross(p21);
        let center = Point::from_cartesian(cross.x, cross.y, cross.z);
        let radius = center.distance(&self.arc_point(arc0));
        let theta = center.theta().value() + radius;
        if theta >= min_theta {
            let point = Point::from_angles(Angle::from(theta), center.phi().clone());
            let circle = self.events.add_circle(arc1, center, point);
            self.beach.set_circle(arc1, Some(circle));
            true
        } else {
            false
        }
    }

    fn detach_circle(&mut self, arc: Arc) -> bool {
        if let Some(event) = self.beach.circle(arc) {
            self.events.set_invalid(event, true);
            self.beach.set_circle(arc, None);
            true
        } else {
            false
        }
    }

    fn finish(&mut self) {
        for edge in self.diagram.edges() {
            let mut common = Vec::new();
            let (vertex0, vertex1) = self.diagram.edge_vertices(edge);
            for &face0 in self.diagram.vertex_faces(vertex0) {
                for &face1 in self.diagram.vertex_faces(vertex1) {
                    if face0 == face1 {
                        common.push(face0);
                    }
                }
            }
            assert_eq!(common.len(), 2);
            self.diagram.set_edge_faces(edge, common[0], common[1]);
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum Error {
    FewPoints,
}

pub fn build(points: &[Point], relaxations: usize) -> Result<Diagram, Error> {
    Builder::new(points)?.build(relaxations)
}

<commit_msg>Remove useless checks in arcs intersection<commit_after>use std::cmp::Ordering;
use angle::Angle;
use point::Point;
use events::{Events, EventKind, Circle};
use beach::{Beach, Arc, ArcStart};
use diagram::{Diagram, Vertex, Face};

struct Builder {
    events: Events,
    beach: Beach,
    diagram: Diagram,
    scan_theta: Angle,
    temporary: Vec<Vertex>,
}

impl Builder {
    fn new(points: &[Point]) -> Result<Self, Error> {
        if points.len() < 2 {
            return Err(Error::FewPoints);
        }
        let mut builder = Builder {
            events: Events::default(),
            beach: Beach::default(),
            diagram: Diagram::default(),
            scan_theta: Angle::from(0.0),
            temporary: Vec::new(),
        };
        for &point in points {
            let face = builder.diagram.add_face(point);
            builder.events.add_site(face, point);
        }
        Ok(builder)
    }

    pub fn build(mut self, relaxations: usize) -> Result<Diagram, Error> {
        self.build_iter();
        for _ in 1..relaxations {
            self.reset();
            self.build_iter();
        }
        self.finish();
        Ok(self.diagram)
    }

    fn build_iter(&mut self) {
        while let Some(event) = self.events.pop() {
            //println!("{:#?}", event);
            let point = event.point;
            self.scan_theta = *point.theta();
            match event.kind {
                EventKind::Site(face) => self.handle_site_event(face, point),
                EventKind::Circle(event) => self.handle_circle_event(event),
            }
        }
    }

    fn reset(&mut self) {
        self.diagram.reset_faces();
        self.diagram.clear_vertices();
        self.diagram.clear_edges();
        for face in self.diagram.faces() {
            self.events.add_site(face, *self.diagram.face_point(face));
        }
        self.temporary.clear();
        self.events.clear();
        self.beach.clear();
        self.scan_theta = Angle::from(0.0);
    }

    fn arc_point(&self, arc: Arc) -> &Point {
        &self.diagram.face_point(self.beach.face(arc))
    }

    fn create_temporary(&mut self, arc0: Arc, arc1: Arc) {
        let index = self.temporary.len();
        self.temporary.push(Vertex::invalid());
        self.beach.set_start(arc0, ArcStart::Temporary(index));
        self.beach.set_start(arc1, ArcStart::Temporary(index));
    }

    fn handle_site_event(&mut self, face: Face, point: Point) {
        if let Some(mut arc) = self.beach.root() {
            if self.beach.len() == 1 {
                self.beach.insert_after(Some(arc), face);
                let arc0 = self.beach.first();
                let arc1 = self.beach.last();
                self.create_temporary(arc0, arc1);
                return;
            }
            let mut use_tree = true;
            loop {
                let prev_arc = self.beach.prev(arc);
                let next_arc = self.beach.next(arc);
                let phi_start = self.arcs_intersection(prev_arc, arc);
                let phi_end = self.arcs_intersection(arc, next_arc);
                match point.phi().is_in_range(phi_start, phi_end) {
                    Ordering::Less => {
                        if use_tree {
                            if let Some(left) = self.beach.left(arc) {
                                arc = left;
                            } else {
                                // the tree has failed us, do the linear search from now on.
                                arc = self.beach.last();
                                use_tree = false;
                            }
                        } else {
                            arc = self.beach.prev(arc);
                        }
                    },
                    Ordering::Greater => {
                        if use_tree {
                            if let Some(right) = self.beach.right(arc) {
                                arc = right;
                            } else {
                                // the tree has failed us, do the linear search from now on.
                                arc = self.beach.first();
                                use_tree = false;
                            }
                        } else {
                            arc = self.beach.next(arc);
                        }
                    },
                    Ordering::Equal => {
                        self.detach_circle(arc);
                        let twin = {
                            let face = self.beach.face(arc);
                            let a = if prev_arc == self.beach.last() {
                                None
                            } else {
                                Some(prev_arc)
                            };
                            self.beach.insert_after(a, face)
                        };
                        let new_arc = self.beach.insert_after(Some(twin), face);
                        self.create_temporary(twin, new_arc);
                        self.attach_circle(prev_arc, twin, new_arc, point.theta().value());
                        self.attach_circle(new_arc, arc, next_arc, point.theta().value());
                        if self.detach_circle(prev_arc) {
                            let prev_prev = self.beach.prev(prev_arc);
                            self.attach_circle(prev_prev, prev_arc, twin, ::std::f64::MIN);
                        }
                        break;
                    }
                }
            }
        } else {
            self.beach.insert_after(None, face);
        }
    }

    fn merge_arcs(&mut self, arc0: Arc, arc1: Arc, arc2: Arc, vertex: Option<Vertex>) {
        let (face0, face1, face2) = (self.beach.face(arc0), self.beach.face(arc1), self.beach.face(arc2));
        if face0 != face1 && face1 != face2 && face2 != face0 {
            let theta = self.scan_theta.value();
            if self.attach_circle(arc0, arc1, arc2, theta) {
                if let Some(vertex) = vertex {
                    self.beach.set_start(arc1, ArcStart::Vertex(vertex));
                }
            }
        }
    }

    fn edge_from_arc(&mut self, arc: Arc, end: Vertex) {
        match self.beach.start(arc) {
            ArcStart::Temporary(index) => {
                let start = self.temporary[index];
                if start.is_invalid() {
                    self.temporary[index] = end;
                } else {
                    self.diagram.add_edge(start, end);
                }
            },
            ArcStart::Vertex(start) => {
                self.diagram.add_edge(start, end);
            },
            ArcStart::None => {},
        };
    }

    fn handle_circle_event(&mut self, event: Circle) {
        if self.events.is_invalid(event) {
            return;
        }
        let arc = self.events.arc(event);
        assert_eq!(self.beach.circle(arc), Some(event));
        let prev = self.beach.prev(arc);
        let next = self.beach.next(arc);
        self.detach_circle(prev);
        self.detach_circle(next);
        let point = self.events.center(event);
        let vertex = self.diagram.add_vertex(point, &[self.beach.face(prev), self.beach.face(arc), self.beach.face(next)]);
        self.edge_from_arc(prev, vertex);
        self.edge_from_arc(arc, vertex);
        self.beach.remove(arc);
        if self.beach.prev(prev) == next {
            self.edge_from_arc(next, vertex);
            self.beach.remove(prev);
            self.beach.remove(next);
        } else {
            let prev_prev = self.beach.prev(prev);
            let next_next = self.beach.next(next);
            self.merge_arcs(prev_prev, prev, next, Some(vertex));
            self.merge_arcs(prev, next, next_next, None);
        }
    }

    fn arcs_intersection(&self, arc0: Arc, arc1: Arc) -> f64 {
        let point0 = self.arc_point(arc0);
        let theta0 = point0.theta();
        let phi0 = point0.phi();
        let point1 = self.arc_point(arc1);
        let theta1 = point1.theta();
        let phi1 = point1.phi();
        let u1 = (self.scan_theta.cos() - theta1.cos()) * theta0.sin();
        let u2 = (self.scan_theta.cos() - theta0.cos()) * theta1.sin();
        let a1 = u1 * phi0.cos();
        let a2 = u2 * phi1.cos();
        let a = a1 - a2;
        let b1 = u1 * phi0.sin();
        let b2 = u2 * phi1.sin();
        let b = b1 - b2;
        let c = (theta0.cos() - theta1.cos()) * self.scan_theta.sin();
        let length = (a * a + b * b).sqrt();
        assert!(a.abs() <= length || c.abs() <= length);
        let gamma = a.atan2(b);
        let phi_int_plus_gamma1 = (c / length).asin();
        Angle::wrap(phi_int_plus_gamma1 - gamma)
    }

    fn attach_circle(&mut self, arc0: Arc, arc1: Arc, arc2: Arc, min_theta: f64) -> bool {
        let p1 = self.arc_point(arc1).position();
        let p01 = self.arc_point(arc0).position() - p1;
        let p21 = self.arc_point(arc2).position() - p1;
        let cross = p01.cross(p21);
        let center = Point::from_cartesian(cross.x, cross.y, cross.z);
        let radius = center.distance(&self.arc_point(arc0));
        let theta = center.theta().value() + radius;
        if theta >= min_theta {
            let point = Point::from_angles(Angle::from(theta), center.phi().clone());
            let circle = self.events.add_circle(arc1, center, point);
            self.beach.set_circle(arc1, Some(circle));
            true
        } else {
            false
        }
    }

    fn detach_circle(&mut self, arc: Arc) -> bool {
        if let Some(event) = self.beach.circle(arc) {
            self.events.set_invalid(event, true);
            self.beach.set_circle(arc, None);
            true
        } else {
            false
        }
    }

    fn finish(&mut self) {
        for edge in self.diagram.edges() {
            let mut common = Vec::new();
            let (vertex0, vertex1) = self.diagram.edge_vertices(edge);
            for &face0 in self.diagram.vertex_faces(vertex0) {
                for &face1 in self.diagram.vertex_faces(vertex1) {
                    if face0 == face1 {
                        common.push(face0);
                    }
                }
            }
            assert_eq!(common.len(), 2);
            self.diagram.set_edge_faces(edge, common[0], common[1]);
        }
    }
}

#[derive(PartialEq, Debug)]
pub enum Error {
    FewPoints,
}

pub fn build(points: &[Point], relaxations: usize) -> Result<Diagram, Error> {
    Builder::new(points)?.build(relaxations)
}

<|endoftext|>


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

use canvas_traits::media::*;
use std::thread;

/// GL player threading API entry point that lives in the
/// constellation.
///
/// It allows to get a GLPlayerThead handle for each script pipeline.
pub use crate::media_mode::GLPlayerThreads;

/// A GLPlayerThrx1ead manages the life cycle and message multiplexign of
/// a set of video players with GL render.
pub struct GLPlayerThread ();

impl GLPlayerThread {
    pub fn new() -> Self {
        GLPlayerThread()
    }

    pub fn start() -> GLPlayerSender<GLPlayerMsg> {
        let (sender, receiver) = glplayer_channel::<GLPlayerMsg>().unwrap();
        thread::Builder::new()
            .name("GLPlayerThread".to_owned())
            .spawn(move || {
                let renderer = GLPlayerThread::new();
                loop {
                    let msg = receiver.recv().unwrap();
                    let exit = renderer.handle_msg(msg);
                    if exit {
                        return;
                    }
                }
            })
            .expect("Thread spawning failed");

        sender
    }

    /// Handles a generic WebGLMsg message
    #[inline]
    fn handle_msg(&self, msg: GLPlayerMsg) -> bool {
        trace!("processing {:?}", msg);
        match msg {
            GLPlayerMsg::Exit => return true,
            _ => (),
        }

        false
    }
}
<commit_msg>GLPlayer thread API implementation<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use canvas_traits::media::*;
use fnv::FnvHashMap;
use std::thread;

/// GL player threading API entry point that lives in the
/// constellation.
///
/// It allows to get a GLPlayerThead handle for each script pipeline.
pub use crate::media_mode::GLPlayerThreads;

/// A GLPlayerThrx1ead manages the life cycle and message multiplexign of
/// a set of video players with GL render.
pub struct GLPlayerThread {
    // Map of live players.
    players: FnvHashMap<u64, GLPlayerSender<GLPlayerMsgForward>>,
    /// Id generator for new WebGLContexts.
    next_player_id: u64,
}

impl GLPlayerThread {
    pub fn new() -> Self {
        GLPlayerThread {
            players: Default::default(),
            next_player_id: 1,
        }
    }

    pub fn start() -> GLPlayerSender<GLPlayerMsg> {
        let (sender, receiver) = glplayer_channel::<GLPlayerMsg>().unwrap();
        thread::Builder::new()
            .name("GLPlayerThread".to_owned())
            .spawn(move || {
                let mut renderer = GLPlayerThread::new();
                loop {
                    let msg = receiver.recv().unwrap();
                    let exit = renderer.handle_msg(msg);
                    if exit {
                        return;
                    }
                }
            })
            .expect("Thread spawning failed");

        sender
    }

    /// Handles a generic WebGLMsg message
    #[inline]
    fn handle_msg(&mut self, msg: GLPlayerMsg) -> bool {
        trace!("processing {:?}", msg);
        match msg {
            GLPlayerMsg::RegisterPlayer(sender) => {
                let id = self.next_player_id;
                self.players.insert(id, sender.clone());
                sender.send(GLPlayerMsgForward::PlayerId(id)).unwrap();
                self.next_player_id += 1;
            },
            GLPlayerMsg::UnregisterPlayer(id) => {
                if self.players.remove(&id).is_none() {
                    warn!("Tried to remove an unknown player");
                }
            },
            GLPlayerMsg::Lock(id, handler_sender) => {
                self.players.get(&id).map(|sender| {
                    sender.send(GLPlayerMsgForward::Lock(handler_sender)).ok();
                });
            },
            GLPlayerMsg::Unlock(id) => {
                self.players.get(&id).map(|sender| {
                    sender.send(GLPlayerMsgForward::Unlock()).ok();
                });
            },
            GLPlayerMsg::Exit => return true,
        }

        false
    }
}
<|endoftext|>