<commit_before>//! A rustification of the `AudioStreamBasicDescription` type.
//!
//! Find the original `AudioStreamBasicDescription` reference [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/c/tdef/AudioStreamBasicDescription).

use bindings::audio_unit as au;
use error::{self, Error};
use super::audio_format::AudioFormat;
use super::SampleFormat;

/// A representation of the AudioStreamBasicDescription specifically for use with the AudioUnit API.
///
/// By using a type specific to the audio unit API, we can remove a lot of unnecessary boilerplate
/// that is normally associated with the AudioStreamBasicDescription.
///
/// Seeing as `LinearPCM` data (the `AudioFormat` used by the `AudioUnit` API) implies a single
/// frame per packet, we can infer many of the fields in an ASBD from the sample type.
///
/// `bytes_per_packet` = size_of::<S>()
/// `bytes_per_frame` = size_of::<S>()
/// `frames_per_packet` = 1
/// `bits_per_channel` = size_of::<S>() * 8
#[derive(Copy, Clone, Debug)]
pub struct StreamFormat {
    pub sample_rate: f64,
    pub sample_format: SampleFormat,
    pub flags: super::audio_format::LinearPCMFlags,
    pub channels_per_frame: u32,
}

impl StreamFormat {

    /// Convert an AudioStreamBasicDescription into a StreamFormat.
    ///
    /// Note: `audio_unit::StreamFormat` exclusively uses the `LinearPCM` `AudioFormat`. This is as
    /// specified in the documentation:
    ///
    /// > Specify kAudioFormatLinearPCM for the mFormatID field. Audio units use uncompressed audio
    /// data, so this is the correct format identifier to use whenever you work with audio units.
    ///
    /// [*Audio Unit Hosting Guide for iOS*](https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/AudioUnitHostingFundamentals/AudioUnitHostingFundamentals.html)
    ///
    /// Returns an `Error` if the `AudioFormat` inferred by the ASBD is not `LinearPCM`.
    ///
    /// Returns an `Error` if the sample format type kkkkkkkkkkkkkkkkkkkkkk
    pub fn from_asbd(asbd: au::AudioStreamBasicDescription) -> Result<StreamFormat, Error> {
        use super::audio_format::linear_pcm_flags;

        const NOT_SUPPORTED: Error = Error::AudioUnit(error::audio_unit::Error::FormatNotSupported);

        let au::Struct_AudioStreamBasicDescription {
            mSampleRate,
            mFormatID,
            mFormatFlags,
            mBytesPerPacket,
            mFramesPerPacket,
            mBytesPerFrame,
            mChannelsPerFrame,
            mBitsPerChannel,
            ..
        } = asbd;

        // Retrieve the LinearPCM flags.
        let flags = match AudioFormat::from_format_and_flag(mFormatID, Some(mFormatFlags)) {
            Some(AudioFormat::LinearPCM(flags)) => flags,
            _ => return Err(NOT_SUPPORTED),
        };

        // Determine the `SampleFormat` to use.
        let sample_format = match SampleFormat::from_flags_and_bytes_per_frame(flags, mBytesPerFrame) {
            Some(sample_format) => sample_format,
            None => return Err(NOT_SUPPORTED),
        };

        Ok(StreamFormat {
            sample_rate: mSampleRate,
            flags: flags,
            sample_format: sample_format,
            channels_per_frame: mChannelsPerFrame,
        })
    }

    /// Convert a StreamFormat into an AudioStreamBasicDescription.
    pub fn to_asbd(self) -> au::AudioStreamBasicDescription {
        let StreamFormat {
            sample_rate,
            flags,
            sample_format,
            channels_per_frame,
        } = self;

        let (format, maybe_flag) = AudioFormat::LinearPCM(flags).to_format_and_flag();

        let flag = maybe_flag.unwrap_or(::std::u32::MAX -2147483647);

        let bytes_per_frame = sample_format.size_in_bytes() as u32;
        const FRAMES_PER_PACKET: u32 = 1;
        let bytes_per_packet = bytes_per_frame * FRAMES_PER_PACKET;
        let bits_per_channel = bytes_per_frame * 8;

        au::AudioStreamBasicDescription {
            mSampleRate: sample_rate,
            mFormatID: format,
            mFormatFlags: flag,
            mBytesPerPacket: bytes_per_packet,
            mFramesPerPacket: FRAMES_PER_PACKET,
            mBytesPerFrame: bytes_per_frame,
            mChannelsPerFrame: channels_per_frame,
            mBitsPerChannel: bits_per_channel,
            mReserved: 0,
        }
    }

}
<commit_msg>Improve docs on StreamFormat type<commit_after>//! A rustification of the `AudioStreamBasicDescription` type.
//!
//! Find the original `AudioStreamBasicDescription` reference [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/c/tdef/AudioStreamBasicDescription).

use bindings::audio_unit as au;
use error::{self, Error};
use super::audio_format::AudioFormat;
use super::SampleFormat;

/// A representation of the AudioStreamBasicDescription specifically for use with the AudioUnit API.
///
/// By using a type specific to the audio unit API, we can remove a lot of unnecessary boilerplate
/// that is normally associated with the AudioStreamBasicDescription.
///
/// Seeing as `LinearPCM` data (the `AudioFormat` used by the `AudioUnit` API) implies a single
/// frame per packet, we can infer many of the fields in an ASBD from the sample type.
///
/// `bytes_per_packet` = size_of::<S>()
/// `bytes_per_frame` = size_of::<S>()
/// `frames_per_packet` = 1
/// `bits_per_channel` = size_of::<S>() * 8
///
/// > A *packet* is a collection of one or more contiguous frames. In linear PCM audio, a packet is
/// always a single frame.
///
/// [from *Core Audio Overview*](https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/CoreAudioOverview/WhatisCoreAudio/WhatisCoreAudio.html)
///
/// > The canonical formats in Core Audio are as follows:
/// >
/// > - iOS input and output: Linear PCM with 16-bit integer samples.
/// > - iOS audio units and other audio processing: Noninterleaved linear PCM with 8.24-bit
/// fixed-point samples
/// > - Mac input and output: Linear PCM with 32-bit floating point samples.
/// > - Mac audio units and other audio processing: Noninterleaved linear PCM with 32-bit floating
/// point samples.
#[derive(Copy, Clone, Debug)]
pub struct StreamFormat {
    /// The number of frames of audio data per second used to represent a signal.
    pub sample_rate: f64,
    /// The sample format used to represent the audio data.
    ///
    /// In OS X, Core Audio xpects audio data to be in native-endian, 32-bit floating-point,
    /// linear PCM format.
    ///
    /// iOS uses integer and fixed-point audio data. The result is faster calculations and less
    /// battery drain when processing audio. iOS provides a Converter audio unit and inclues the
    /// interfaces from Audio Converter Services (TODO: look into exposing this).
    pub sample_format: SampleFormat,
    pub flags: super::audio_format::LinearPCMFlags,
    pub channels_per_frame: u32,
}

impl StreamFormat {

    /// Convert an AudioStreamBasicDescription into a StreamFormat.
    ///
    /// Note: `audio_unit::StreamFormat` exclusively uses the `LinearPCM` `AudioFormat`. This is as
    /// specified in the documentation:
    ///
    /// > Specify kAudioFormatLinearPCM for the mFormatID field. Audio units use uncompressed audio
    /// data, so this is the correct format identifier to use whenever you work with audio units.
    ///
    /// [*Audio Unit Hosting Guide for iOS*](https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/AudioUnitHostingFundamentals/AudioUnitHostingFundamentals.html)
    ///
    /// Returns an `Error` if the `AudioFormat` inferred by the ASBD is not `LinearPCM`.
    ///
    /// Returns an `Error` if the sample format type kkkkkkkkkkkkkkkkkkkkkk
    pub fn from_asbd(asbd: au::AudioStreamBasicDescription) -> Result<StreamFormat, Error> {
        use super::audio_format::linear_pcm_flags;

        const NOT_SUPPORTED: Error = Error::AudioUnit(error::audio_unit::Error::FormatNotSupported);

        let au::Struct_AudioStreamBasicDescription {
            mSampleRate,
            mFormatID,
            mFormatFlags,
            mBytesPerPacket,
            mFramesPerPacket,
            mBytesPerFrame,
            mChannelsPerFrame,
            mBitsPerChannel,
            ..
        } = asbd;

        // Retrieve the LinearPCM flags.
        let flags = match AudioFormat::from_format_and_flag(mFormatID, Some(mFormatFlags)) {
            Some(AudioFormat::LinearPCM(flags)) => flags,
            _ => return Err(NOT_SUPPORTED),
        };

        // Determine the `SampleFormat` to use.
        let sample_format = match SampleFormat::from_flags_and_bytes_per_frame(flags, mBytesPerFrame) {
            Some(sample_format) => sample_format,
            None => return Err(NOT_SUPPORTED),
        };

        Ok(StreamFormat {
            sample_rate: mSampleRate,
            flags: flags,
            sample_format: sample_format,
            channels_per_frame: mChannelsPerFrame,
        })
    }

    /// Convert a StreamFormat into an AudioStreamBasicDescription.
    pub fn to_asbd(self) -> au::AudioStreamBasicDescription {
        let StreamFormat {
            sample_rate,
            flags,
            sample_format,
            channels_per_frame,
        } = self;

        let (format, maybe_flag) = AudioFormat::LinearPCM(flags).to_format_and_flag();

        let flag = maybe_flag.unwrap_or(::std::u32::MAX -2147483647);

        let bytes_per_frame = sample_format.size_in_bytes() as u32;
        const FRAMES_PER_PACKET: u32 = 1;
        let bytes_per_packet = bytes_per_frame * FRAMES_PER_PACKET;
        let bits_per_channel = bytes_per_frame * 8;

        au::AudioStreamBasicDescription {
            mSampleRate: sample_rate,
            mFormatID: format,
            mFormatFlags: flag,
            mBytesPerPacket: bytes_per_packet,
            mFramesPerPacket: FRAMES_PER_PACKET,
            mBytesPerFrame: bytes_per_frame,
            mChannelsPerFrame: channels_per_frame,
            mBitsPerChannel: bits_per_channel,
            mReserved: 0,
        }
    }

}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::cita_protocol::network_message_to_pubsub_message;
use crate::network::{NetworkClient, RemoteMessage};
use crate::node_manager::{AddConnectedNodeReq, InitMsg, NetworkInitReq, NodesManagerClient};
use bytes::BytesMut;
use libproto::{Message as ProtoMessage, TryFrom, TryInto};
use logger::{info, warn};
use tentacle::{
    context::{ServiceContext, SessionContext},
    traits::{ProtocolMeta, ServiceProtocol},
    ProtocolId, SessionId,
};
use tokio::codec::length_delimited::LengthDelimitedCodec;

pub const TRANSFER_PROTOCOL_ID: ProtocolId = 1;

pub struct TransferProtocolMeta {
    id: ProtocolId,
    network_client: NetworkClient,
    nodes_mgr_client: NodesManagerClient,
}

impl TransferProtocolMeta {
    pub fn new(
        id: ProtocolId,
        network_client: NetworkClient,
        nodes_mgr_client: NodesManagerClient,
    ) -> Self {
        TransferProtocolMeta {
            id,
            network_client,
            nodes_mgr_client,
        }
    }
}

impl ProtocolMeta<LengthDelimitedCodec> for TransferProtocolMeta {
    fn id(&self) -> ProtocolId {
        self.id
    }

    fn name(&self) -> String {
        "/cita/transfer".to_owned()
    }

    fn support_versions(&self) -> Vec<String> {
        vec!["0.0.1".to_owned()]
    }

    fn codec(&self) -> LengthDelimitedCodec {
        LengthDelimitedCodec::new()
    }

    fn service_handle(&self) -> Option<Box<dyn ServiceProtocol + Send + 'static>> {
        let handle = Box::new(TransferProtocol {
            proto_id: self.id,
            connected_session_ids: Vec::default(),
            network_client: self.network_client.clone(),
            nodes_mgr_client: self.nodes_mgr_client.clone(),
        });
        Some(handle)
    }
}

struct TransferProtocol {
    proto_id: ProtocolId,
    connected_session_ids: Vec<SessionId>,
    network_client: NetworkClient,
    nodes_mgr_client: NodesManagerClient,
}

impl ServiceProtocol for TransferProtocol {
    fn init(&mut self, _control: &mut ServiceContext) {}

    fn connected(
        &mut self,
        _control: &mut ServiceContext,
        session: &SessionContext,
        version: &str,
    ) {
        info!(
            "[Transfer] Connected proto id [{}] open on session [{}], address: [{}], type: [{:?}], version: {}",
            self.proto_id, session.id, session.address, session.ty, version
        );
        self.connected_session_ids.push(session.id);

        let req = NetworkInitReq::new(session.id);
        self.nodes_mgr_client.network_init(req);

        info!(
            "[Transfer] Connected sessions: {:?}",
            self.connected_session_ids
        );
    }

    fn disconnected(&mut self, _control: &mut ServiceContext, session: &SessionContext) {
        let new_list = self
            .connected_session_ids
            .iter()
            .filter(|&id| id != &session.id)
            .cloned()
            .collect();
        self.connected_session_ids = new_list;

        info!(
            "[Transfer] Disconnected proto id [{}] close on session [{}]",
            self.proto_id, session.id
        );
    }

    fn received(&mut self, _env: &mut ServiceContext, session: &SessionContext, data: Vec<u8>) {
        let mut data = BytesMut::from(data);

        if let Some((key, message)) = network_message_to_pubsub_message(&mut data) {
            if key.eq(&"network.init".to_string()) {
                let msg = InitMsg::from(message);
                let req = AddConnectedNodeReq::new(session.id, session.ty, msg);
                self.nodes_mgr_client.add_connected_node(req);
                return;
            }

            let mut msg = ProtoMessage::try_from(&message).unwrap();
            msg.set_origin(session.id as u32);
            self.network_client
                .handle_remote_message(RemoteMessage::new(key, msg.try_into().unwrap()));
        } else {
            warn!("[Transfer] Cannot convert network message to pubsub message!");
        }
    }
}
<commit_msg>bugfix: network high cpu usage. [skip travis]<commit_after>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::cita_protocol::network_message_to_pubsub_message;
use crate::network::{NetworkClient, RemoteMessage};
use crate::node_manager::{AddConnectedNodeReq, InitMsg, NetworkInitReq, NodesManagerClient};
use bytes::BytesMut;
use libproto::{Message as ProtoMessage, TryFrom, TryInto};
use logger::{info, warn};
use tentacle::{
    context::{ServiceContext, SessionContext},
    traits::{ProtocolMeta, ServiceProtocol},
    ProtocolId, SessionId,
};
use tokio::codec::length_delimited::LengthDelimitedCodec;

pub const TRANSFER_PROTOCOL_ID: ProtocolId = 1;

// Quota (1 byte) = 200,
// Max 20 block in one transfer.
// 512M can support BQL set to 2 ** 32 - 1
pub const MAX_FRAME_LENGTH: usize = 512 * 1024 * 1204;

pub struct TransferProtocolMeta {
    id: ProtocolId,
    network_client: NetworkClient,
    nodes_mgr_client: NodesManagerClient,
}

impl TransferProtocolMeta {
    pub fn new(
        id: ProtocolId,
        network_client: NetworkClient,
        nodes_mgr_client: NodesManagerClient,
    ) -> Self {
        TransferProtocolMeta {
            id,
            network_client,
            nodes_mgr_client,
        }
    }
}

impl ProtocolMeta<LengthDelimitedCodec> for TransferProtocolMeta {
    fn id(&self) -> ProtocolId {
        self.id
    }

    fn name(&self) -> String {
        "/cita/transfer".to_owned()
    }

    fn support_versions(&self) -> Vec<String> {
        vec!["0.0.1".to_owned()]
    }

    fn codec(&self) -> LengthDelimitedCodec {
        let mut codec = LengthDelimitedCodec::new();
        codec.set_max_frame_length(MAX_FRAME_LENGTH);
        codec
    }

    fn service_handle(&self) -> Option<Box<dyn ServiceProtocol + Send + 'static>> {
        let handle = Box::new(TransferProtocol {
            proto_id: self.id,
            connected_session_ids: Vec::default(),
            network_client: self.network_client.clone(),
            nodes_mgr_client: self.nodes_mgr_client.clone(),
        });
        Some(handle)
    }
}

struct TransferProtocol {
    proto_id: ProtocolId,
    connected_session_ids: Vec<SessionId>,
    network_client: NetworkClient,
    nodes_mgr_client: NodesManagerClient,
}

impl ServiceProtocol for TransferProtocol {
    fn init(&mut self, _control: &mut ServiceContext) {}

    fn connected(
        &mut self,
        _control: &mut ServiceContext,
        session: &SessionContext,
        version: &str,
    ) {
        info!(
            "[Transfer] Connected proto id [{}] open on session [{}], address: [{}], type: [{:?}], version: {}",
            self.proto_id, session.id, session.address, session.ty, version
        );
        self.connected_session_ids.push(session.id);

        let req = NetworkInitReq::new(session.id);
        self.nodes_mgr_client.network_init(req);

        info!(
            "[Transfer] Connected sessions: {:?}",
            self.connected_session_ids
        );
    }

    fn disconnected(&mut self, _control: &mut ServiceContext, session: &SessionContext) {
        let new_list = self
            .connected_session_ids
            .iter()
            .filter(|&id| id != &session.id)
            .cloned()
            .collect();
        self.connected_session_ids = new_list;

        info!(
            "[Transfer] Disconnected proto id [{}] close on session [{}]",
            self.proto_id, session.id
        );
    }

    fn received(&mut self, _env: &mut ServiceContext, session: &SessionContext, data: Vec<u8>) {
        let mut data = BytesMut::from(data);

        if let Some((key, message)) = network_message_to_pubsub_message(&mut data) {
            if key.eq(&"network.init".to_string()) {
                let msg = InitMsg::from(message);
                let req = AddConnectedNodeReq::new(session.id, session.ty, msg);
                self.nodes_mgr_client.add_connected_node(req);
                return;
            }

            let mut msg = ProtoMessage::try_from(&message).unwrap();
            msg.set_origin(session.id as u32);
            self.network_client
                .handle_remote_message(RemoteMessage::new(key, msg.try_into().unwrap()));
        } else {
            warn!("[Transfer] Cannot convert network message to pubsub message!");
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 Inderjit Gill

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use lexer::Token;

struct Gene {
    this_is_a_placeholder: i32,
}

struct NodeMeta<'a> {
    gene: Option<Gene>,
    parameter_ast: Vec<Node<'a>>,
    parameter_prefix: Vec<Node<'a>>,
}

#[derive(Debug, Eq, PartialEq)]
pub enum Node<'a> {
    List(Vec<Node<'a>>),
    Vector(Vec<Node<'a>>),
    Int(&'a str),
    Float(&'a str),
    Name(&'a str),
    Label(&'a str),
    String(&'a str),
    Whitespace(&'a str),
    Comment(&'a str),
    Fake,
}

pub fn parse(tokens: Vec<Token>) -> Vec<Node> {
    let mut res = Vec::new();

    let tok = tokens[0];
    let node = match tok {
        Token::Name(n) => Node::Name(n),
        _ => Node::Fake
    };

    res.push(node);

    res
}

#[cfg(test)]
mod tests {
    use super::*;
    use lexer::tokenize;

    fn ast(s: &str) -> Vec<Node> {
        let t = tokenize(s).unwrap();
        let n = parse(t);
        n
    }

    #[test]
    fn test_parser() {
        assert_eq!(ast("hello"), [Node::Name("hello")])
    }
}
<commit_msg>wip: parser<commit_after>// Copyright (C) 2018 Inderjit Gill

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

use error::{SenResult, SenError};
use lexer::{Token, tokenize};

struct Gene {
    this_is_a_placeholder: i32,
}

struct NodeMeta {
    gene: Option<Gene>,
    parameter_ast: Vec<Node>,
    parameter_prefix: Vec<Node>,
}

#[derive(Debug, PartialEq)]
pub enum Node {
    List(Vec<Node>),
    Vector(Vec<Node>),
    Int(String),
    Float(f32),
    Name(String),
    Label(String),
    String(String),
    Whitespace(String),
    Comment(String),
}

struct NodeAndRemainder<'a> {
    node: Node,
    tokens: &'a [Token<'a>],
}

// At the first token after a Token::ParenStart
//
fn eat_list<'a>(t: &'a [Token<'a>]) -> SenResult<NodeAndRemainder<'a>> {
    let mut tokens = t;
    let mut res: Vec<Node> = Vec::new();

    loop {
        match tokens[0] {
            Token::ParenEnd => return Ok(NodeAndRemainder {
                node: Node::List(res),
                tokens: &tokens[1..],
            }),
            _ => {
                match eat_token(tokens) {
                    Ok(nar) => {
                        res.push(nar.node);
                        tokens = nar.tokens;
                    },
                    Err(e) => return Err(e)
                }
            }
        }
    }
}

fn eat_token<'a>(tokens: &'a[Token<'a>]) -> SenResult<NodeAndRemainder<'a>> {
    match tokens[0] {
        Token::Name(txt) =>
            if tokens.len() > 1 && tokens[1] == Token::Colon {
                Ok(NodeAndRemainder {
                    node: Node::Label(txt.to_string()),
                    tokens: &tokens[2..],
                })
            } else {
                Ok(NodeAndRemainder {
                    node: Node::Name(txt.to_string()),
                    tokens: &tokens[1..],
                })
            },
        Token::Number(txt) => Ok(NodeAndRemainder {
            node: Node::Float(txt.parse().unwrap()), // todo: fix unwrap
            tokens: &tokens[1..],
        }),
        Token::Whitespace(ws) => Ok(NodeAndRemainder {
            node: Node::Whitespace(ws.to_string()),
            tokens: &tokens[1..],
        }),
        Token::Comment(comment) => Ok(NodeAndRemainder {
            node: Node::Comment(comment.to_string()),
            tokens: &tokens[1..],
        }),
        Token::ParenStart => eat_list(&tokens[1..]),
        _ => Err(SenError::GeneralError),
    }

}

pub fn parse(s: &str) -> SenResult<Vec<Node>> {
    let t = tokenize(s)?;

    let mut tokens = t.as_slice();
    let mut res = Vec::new();

    while tokens.len() > 0 {
        match eat_token(tokens) {
            Ok(nar) => {
                res.push(nar.node);
                tokens = nar.tokens;
            },
            Err(e) => return Err(e)
        }
    }

    Ok(res)
}

#[cfg(test)]
mod tests {
    use super::*;

    fn ast(s: &str) -> Vec<Node> {
        parse(s).unwrap()
    }

    #[test]
    fn test_parser() {
        assert_eq!(ast("hello"),
                   [Node::Name("hello".to_string())]);
        assert_eq!(ast("hello world"),
                   [Node::Name("hello".to_string()),
                    Node::Whitespace(" ".to_string()),
                    Node::Name("world".to_string())]);
        assert_eq!(ast("hello: world"),
                   [Node::Label("hello".to_string()),
                    Node::Whitespace(" ".to_string()),
                    Node::Name("world".to_string())]);
        assert_eq!(ast("42 102"),
                   [Node::Float(42.0),
                    Node::Whitespace(" ".to_string()),
                    Node::Float(102.0)]);

        assert_eq!(ast("hello world ; some comment"),
                   [Node::Name("hello".to_string()),
                    Node::Whitespace(" ".to_string()),
                    Node::Name("world".to_string()),
                    Node::Whitespace(" ".to_string()),
                    Node::Comment(" some comment".to_string())]);

        assert_eq!(ast("(hello world)"),
                   [Node::List(vec![Node::Name("hello".to_string()),
                                    Node::Whitespace(" ".to_string()),
                                    Node::Name("world".to_string())])]);

        assert_eq!(ast("(hello world (1 2 3))"),
                   [Node::List(vec![Node::Name("hello".to_string()),
                                    Node::Whitespace(" ".to_string()),
                                    Node::Name("world".to_string()),
                                    Node::Whitespace(" ".to_string()),
                                    Node::List(vec![Node::Float(1.0),
                                                    Node::Whitespace(" ".to_string()),
                                                    Node::Float(2.0),
                                                    Node::Whitespace(" ".to_string()),
                                                    Node::Float(3.0)])])]);

    }
}
<|endoftext|>


<commit_before>use {Backend, QueueFamily};
use native;
use device::{Device, PhysicalDevice};

use std::mem;
use std::sync::{Arc, Mutex};

use hal::{self, format, image};
use hal::{Backbuffer, SwapchainConfig};
use hal::window::Extent2D;

use metal::{self, MTLPixelFormat, MTLTextureUsage};
use objc::runtime::{Object};
use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::dictionary::CFDictionary;
use core_foundation::number::CFNumber;
use core_graphics::base::CGFloat;
use core_graphics::geometry::CGRect;
use cocoa::foundation::{NSRect};
use io_surface::{self, IOSurface};

pub struct Surface(pub(crate) Arc<SurfaceInner>);

pub(crate) struct SurfaceInner {
    pub(crate) nsview: *mut Object,
    pub(crate) render_layer: Mutex<*mut Object>,
}

unsafe impl Send for SurfaceInner {}
unsafe impl Sync for SurfaceInner {}

impl Drop for SurfaceInner {
    fn drop(&mut self) {
        unsafe { msg_send![self.nsview, release]; }
    }
}

pub struct Swapchain {
     surface: Arc<SurfaceInner>,
    _size_pixels: (u64, u64),
    io_surfaces: Vec<IOSurface>,
    frame_index: usize,
    present_index: usize,
}

unsafe impl Send for Swapchain {}
unsafe impl Sync for Swapchain {}

impl Swapchain {
    pub(crate) fn present(&mut self) -> (&SurfaceInner, &mut IOSurface) {
        let id = self.present_index;
        self.present_index = (id + 1) % self.io_surfaces.len();
        (&*self.surface, &mut self.io_surfaces[id])
    }
}

#[allow(bad_style)]
const kCVPixelFormatType_32RGBA: u32 = (b'R' as u32) << 24 | (b'G' as u32) << 16 | (b'B' as u32) << 8 | b'A' as u32;

impl hal::Surface<Backend> for Surface {
    fn kind(&self) -> image::Kind {
        let (width, height) = self.pixel_dimensions();

        image::Kind::D2(width, height, 1, 1)
    }

    fn capabilities_and_formats(
        &self, _: &PhysicalDevice,
    ) -> (hal::SurfaceCapabilities, Option<Vec<format::Format>>) {
        let caps = hal::SurfaceCapabilities {
            image_count: 1..8,
            current_extent: None,
            extents: Extent2D { width: 4, height: 4} .. Extent2D { width: 4096, height: 4096 },
            max_image_layers: 1,
        };
        let formats = Some(vec![format::Format::Rgba8Srgb]);
        (caps, formats)
    }

    fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
        true // TODO: Not sure this is the case, don't know associativity of IOSurface
    }
}

impl Surface {
    fn pixel_dimensions(&self) -> (image::Size, image::Size) {
        unsafe {
            // NSView bounds are measured in DIPs
            let bounds: NSRect = msg_send![self.0.nsview, bounds];
            (bounds.size.width as _, bounds.size.height as _)
        }
    }
}

impl Device {
    pub fn build_swapchain(
        &self,
        surface: &mut Surface,
        config: SwapchainConfig,
    ) -> (Swapchain, Backbuffer<Backend>) {
        let (mtl_format, cv_format) = match config.color_format {
            format::Format::Rgba8Srgb => (MTLPixelFormat::RGBA8Unorm_sRGB, kCVPixelFormatType_32RGBA),
            _ => panic!("unsupported backbuffer format"), // TODO: more formats
        };

        let render_layer_borrow = surface.0.render_layer.lock().unwrap();
        let render_layer = *render_layer_borrow;
        let nsview = surface.0.nsview;
        let pixel_size = config.color_format.base_format().0.desc().bits as i32 / 8;

        unsafe {
            // Update render layer size
            let view_points_size: CGRect = msg_send![nsview, bounds];
            msg_send![render_layer, setBounds: view_points_size];
            let view_window: *mut Object = msg_send![nsview, window];
            if view_window.is_null() {
                panic!("surface is not attached to a window");
            }
            let scale_factor: CGFloat = msg_send![view_window, backingScaleFactor];
            msg_send![render_layer, setContentsScale: scale_factor];

            info!("view points size {:?} scale factor {:?}", view_points_size, scale_factor);
            let pixel_width = (view_points_size.size.width * scale_factor) as u64;
            let pixel_height = (view_points_size.size.height * scale_factor) as u64;

            info!("allocating {} IOSurface backbuffers of size {}x{} with pixel format 0x{:x}", config.image_count, pixel_width, pixel_height, cv_format);
            // Create swap chain surfaces
            let io_surfaces: Vec<_> = (0..config.image_count).map(|_| {
                let dict = CFDictionary::from_CFType_pairs(&[
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfaceWidth), CFNumber::from(pixel_width as i32)),
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfaceHeight), CFNumber::from(pixel_height as i32)),
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfaceBytesPerRow), CFNumber::from(pixel_width as i32 * pixel_size)),
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfaceBytesPerElement), CFNumber::from(pixel_size)),
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfacePixelFormat), CFNumber::from(cv_format as i32)),
                ]);
                //Note: the transmute is totally bonkers here
                io_surface::new(mem::transmute(&dict))
            }).collect();

            let backbuffer_descriptor = metal::TextureDescriptor::new();
            backbuffer_descriptor.set_pixel_format(mtl_format);
            backbuffer_descriptor.set_width(pixel_width);
            backbuffer_descriptor.set_height(pixel_height);
            backbuffer_descriptor.set_usage(MTLTextureUsage::MTLTextureUsageRenderTarget);

            let images = io_surfaces.iter().map(|surface| {
                let mapped_texture: metal::Texture = msg_send![self.device.as_ref(),
                    newTextureWithDescriptor: &*backbuffer_descriptor
                    iosurface: surface.obj
                    plane: 0
                ];
                native::Image {
                    raw: mapped_texture,
                    extent: image::Extent {
                        width: pixel_width as _,
                        height: pixel_height as _,
                        depth: 1,
                    },
                    format_desc: config.color_format.surface_desc(),
                    mtl_format,
                    mtl_type: metal::MTLTextureType::D2,
                }
            }).collect();

            let swapchain = Swapchain {
                surface: surface.0.clone(),
                _size_pixels: (pixel_width, pixel_height),
                io_surfaces,
                frame_index: 0,
                present_index: 0,
            };

            (swapchain, Backbuffer::Images(images))
        }
    }
}

impl hal::Swapchain<Backend> for Swapchain {
    fn acquire_frame(&mut self, sync: hal::FrameSync<Backend>) -> hal::Frame {
        unsafe {
            match sync {
                hal::FrameSync::Semaphore(semaphore) => {
                    // FIXME: this is definitely wrong
                    native::dispatch_semaphore_signal(semaphore.0);
                },
                hal::FrameSync::Fence(_fence) => unimplemented!(),
            }

            let frame = hal::Frame::new(self.frame_index % self.io_surfaces.len());
            self.frame_index += 1;
            frame
        }
    }
}

<commit_msg>metal: Fix Surface dimensions with retina<commit_after>use {Backend, QueueFamily};
use native;
use device::{Device, PhysicalDevice};

use std::mem;
use std::sync::{Arc, Mutex};

use hal::{self, format, image};
use hal::{Backbuffer, SwapchainConfig};
use hal::window::Extent2D;

use metal::{self, MTLPixelFormat, MTLTextureUsage};
use objc::runtime::{Object};
use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::dictionary::CFDictionary;
use core_foundation::number::CFNumber;
use core_graphics::base::CGFloat;
use core_graphics::geometry::CGRect;
use cocoa::foundation::{NSRect};
use io_surface::{self, IOSurface};

pub struct Surface(pub(crate) Arc<SurfaceInner>);

pub(crate) struct SurfaceInner {
    pub(crate) nsview: *mut Object,
    pub(crate) render_layer: Mutex<*mut Object>,
}

unsafe impl Send for SurfaceInner {}
unsafe impl Sync for SurfaceInner {}

impl Drop for SurfaceInner {
    fn drop(&mut self) {
        unsafe { msg_send![self.nsview, release]; }
    }
}

pub struct Swapchain {
     surface: Arc<SurfaceInner>,
    _size_pixels: (u64, u64),
    io_surfaces: Vec<IOSurface>,
    frame_index: usize,
    present_index: usize,
}

unsafe impl Send for Swapchain {}
unsafe impl Sync for Swapchain {}

impl Swapchain {
    pub(crate) fn present(&mut self) -> (&SurfaceInner, &mut IOSurface) {
        let id = self.present_index;
        self.present_index = (id + 1) % self.io_surfaces.len();
        (&*self.surface, &mut self.io_surfaces[id])
    }
}

#[allow(bad_style)]
const kCVPixelFormatType_32RGBA: u32 = (b'R' as u32) << 24 | (b'G' as u32) << 16 | (b'B' as u32) << 8 | b'A' as u32;

impl hal::Surface<Backend> for Surface {
    fn kind(&self) -> image::Kind {
        let (width, height) = self.pixel_dimensions();

        image::Kind::D2(width, height, 1, 1)
    }

    fn capabilities_and_formats(
        &self, _: &PhysicalDevice,
    ) -> (hal::SurfaceCapabilities, Option<Vec<format::Format>>) {
        let caps = hal::SurfaceCapabilities {
            image_count: 1..8,
            current_extent: None,
            extents: Extent2D { width: 4, height: 4} .. Extent2D { width: 4096, height: 4096 },
            max_image_layers: 1,
        };
        let formats = Some(vec![format::Format::Rgba8Srgb]);
        (caps, formats)
    }

    fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
        true // TODO: Not sure this is the case, don't know associativity of IOSurface
    }
}

impl Surface {
    fn pixel_dimensions(&self) -> (image::Size, image::Size) {
        unsafe {
            // NSView bounds are measured in DIPs
            let bounds: NSRect = msg_send![self.0.nsview, bounds];
            let bounds_pixel: NSRect = msg_send![self.0.nsview, convertRectToBacking:bounds];
            (bounds_pixel.size.width as _, bounds_pixel.size.height as _)
        }
    }
}

impl Device {
    pub fn build_swapchain(
        &self,
        surface: &mut Surface,
        config: SwapchainConfig,
    ) -> (Swapchain, Backbuffer<Backend>) {
        let (mtl_format, cv_format) = match config.color_format {
            format::Format::Rgba8Srgb => (MTLPixelFormat::RGBA8Unorm_sRGB, kCVPixelFormatType_32RGBA),
            _ => panic!("unsupported backbuffer format"), // TODO: more formats
        };

        let render_layer_borrow = surface.0.render_layer.lock().unwrap();
        let render_layer = *render_layer_borrow;
        let nsview = surface.0.nsview;
        let pixel_size = config.color_format.base_format().0.desc().bits as i32 / 8;

        unsafe {
            // Update render layer size
            let view_points_size: CGRect = msg_send![nsview, bounds];
            msg_send![render_layer, setBounds: view_points_size];
            let view_window: *mut Object = msg_send![nsview, window];
            if view_window.is_null() {
                panic!("surface is not attached to a window");
            }
            let scale_factor: CGFloat = msg_send![view_window, backingScaleFactor];
            msg_send![render_layer, setContentsScale: scale_factor];

            info!("view points size {:?} scale factor {:?}", view_points_size, scale_factor);
            let pixel_width = (view_points_size.size.width * scale_factor) as u64;
            let pixel_height = (view_points_size.size.height * scale_factor) as u64;

            info!("allocating {} IOSurface backbuffers of size {}x{} with pixel format 0x{:x}", config.image_count, pixel_width, pixel_height, cv_format);
            // Create swap chain surfaces
            let io_surfaces: Vec<_> = (0..config.image_count).map(|_| {
                let dict = CFDictionary::from_CFType_pairs(&[
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfaceWidth), CFNumber::from(pixel_width as i32)),
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfaceHeight), CFNumber::from(pixel_height as i32)),
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfaceBytesPerRow), CFNumber::from(pixel_width as i32 * pixel_size)),
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfaceBytesPerElement), CFNumber::from(pixel_size)),
                    (CFString::wrap_under_get_rule(io_surface::kIOSurfacePixelFormat), CFNumber::from(cv_format as i32)),
                ]);
                //Note: the transmute is totally bonkers here
                io_surface::new(mem::transmute(&dict))
            }).collect();

            let backbuffer_descriptor = metal::TextureDescriptor::new();
            backbuffer_descriptor.set_pixel_format(mtl_format);
            backbuffer_descriptor.set_width(pixel_width);
            backbuffer_descriptor.set_height(pixel_height);
            backbuffer_descriptor.set_usage(MTLTextureUsage::MTLTextureUsageRenderTarget);

            let images = io_surfaces.iter().map(|surface| {
                let mapped_texture: metal::Texture = msg_send![self.device.as_ref(),
                    newTextureWithDescriptor: &*backbuffer_descriptor
                    iosurface: surface.obj
                    plane: 0
                ];
                native::Image {
                    raw: mapped_texture,
                    extent: image::Extent {
                        width: pixel_width as _,
                        height: pixel_height as _,
                        depth: 1,
                    },
                    format_desc: config.color_format.surface_desc(),
                    mtl_format,
                    mtl_type: metal::MTLTextureType::D2,
                }
            }).collect();

            let swapchain = Swapchain {
                surface: surface.0.clone(),
                _size_pixels: (pixel_width, pixel_height),
                io_surfaces,
                frame_index: 0,
                present_index: 0,
            };

            (swapchain, Backbuffer::Images(images))
        }
    }
}

impl hal::Swapchain<Backend> for Swapchain {
    fn acquire_frame(&mut self, sync: hal::FrameSync<Backend>) -> hal::Frame {
        unsafe {
            match sync {
                hal::FrameSync::Semaphore(semaphore) => {
                    // FIXME: this is definitely wrong
                    native::dispatch_semaphore_signal(semaphore.0);
                },
                hal::FrameSync::Fence(_fence) => unimplemented!(),
            }

            let frame = hal::Frame::new(self.frame_index % self.io_surfaces.len());
            self.frame_index += 1;
            frame
        }
    }
}

<|endoftext|>


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

use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLInputElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLFieldSetElementDerived};
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, ResultRootable};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::attr::{AttrHelpers};
use dom::document::{Document, DocumentHelpers};
use dom::element::{AttributeHandlers, Element, HTMLInputElementTypeId};
use dom::event::Event;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, document_from_node};
use dom::virtualmethods::VirtualMethods;

use servo_util::str::{DOMString, parse_unsigned_integer};
use string_cache::Atom;

use std::ascii::OwnedStrAsciiExt;
use std::cell::{Cell, RefCell};
use std::mem;

static DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
static DEFAULT_RESET_VALUE: &'static str = "Reset";

#[jstraceable]
#[deriving(PartialEq)]
enum InputType {
    InputButton(Option<&'static str>),
    InputText,
    InputFile,
    InputImage,
    InputCheckbox,
    InputRadio,
    InputPassword
}

#[jstraceable]
#[must_root]
pub struct HTMLInputElement {
    pub htmlelement: HTMLElement,
    input_type: Cell<InputType>,
    checked: Cell<bool>,
    uncommitted_value: RefCell<Option<String>>,
    value: RefCell<Option<String>>,
    size: Cell<u32>,
}

impl HTMLInputElementDerived for EventTarget {
    fn is_htmlinputelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLInputElementTypeId))
    }
}

static DEFAULT_INPUT_SIZE: u32 = 20;

impl HTMLInputElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLInputElement {
        HTMLInputElement {
            htmlelement: HTMLElement::new_inherited(HTMLInputElementTypeId, localName, prefix, document),
            input_type: Cell::new(InputText),
            checked: Cell::new(false),
            uncommitted_value: RefCell::new(None),
            value: RefCell::new(None),
            size: Cell::new(DEFAULT_INPUT_SIZE),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLInputElement> {
        let element = HTMLInputElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLInputElementBinding::Wrap)
    }
}

pub trait LayoutHTMLInputElementHelpers {
    unsafe fn get_value_for_layout(&self) -> String;
    unsafe fn get_size_for_layout(&self) -> u32;
}

impl LayoutHTMLInputElementHelpers for JS<HTMLInputElement> {
    #[allow(unrooted_must_root)]
    unsafe fn get_value_for_layout(&self) -> String {
        unsafe fn get_raw_value(input: &JS<HTMLInputElement>) -> Option<String> {
            mem::transmute::<&RefCell<Option<String>>, &Option<String>>(&(*input.unsafe_get()).value).clone()
        }

        match (*self.unsafe_get()).input_type.get() {
            InputCheckbox | InputRadio => "".to_string(),
            InputFile | InputImage => "".to_string(),
            InputButton(ref default) => get_raw_value(self)
                                          .or_else(|| default.map(|v| v.to_string()))
                                          .unwrap_or_else(|| "".to_string()),
            InputPassword => {
                let raw = get_raw_value(self).unwrap_or_else(|| "".to_string());
                String::from_char(raw.len(), '*')
            }
            _ => get_raw_value(self).unwrap_or_else(|| "".to_string()),
        }
    }

    #[allow(unrooted_must_root)]
    unsafe fn get_size_for_layout(&self) -> u32 {
        (*self.unsafe_get()).size.get()
    }
}

impl<'a> HTMLInputElementMethods for JSRef<'a, HTMLInputElement> {
    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_getter!(Disabled)

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_setter!(SetDisabled, "disabled")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-checked
    make_bool_getter!(Checked)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-checked
    make_bool_setter!(SetChecked, "checked")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-size
    make_uint_getter!(Size)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-size
    make_uint_setter!(SetSize, "size")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-type
    fn Type(self) -> DOMString {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        let ty = elem.get_string_attribute("type").into_ascii_lower();
        // https://html.spec.whatwg.org/multipage/forms.html#attr-input-type
        match ty.as_slice() {
            "hidden" | "search" | "tel" |
            "url" | "email" | "password" |
            "datetime" | "date" | "month" |
            "week" | "time" | "datetime-local" |
            "number" | "range" | "color" |
            "checkbox" | "radio" | "file" |
            "submit" | "image" | "reset" | "button" => ty,
            _ => "text".to_string()
        }
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-type
    make_setter!(SetType, "type")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-value
    make_getter!(Value)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-value
    make_setter!(SetValue, "value")

    // https://html.spec.whatwg.org/multipage/forms.html#attr-fe-name
    make_getter!(Name)

    // https://html.spec.whatwg.org/multipage/forms.html#attr-fe-name
    make_setter!(SetName, "name")
}

trait HTMLInputElementHelpers {
    fn force_relayout(self);
    fn radio_group_updated(self, group: Option<&str>);
    fn get_radio_group(self) -> Option<String>;
    fn update_checked_state(self, checked: bool);
}

fn broadcast_radio_checked(broadcaster: JSRef<HTMLInputElement>, group: Option<&str>) {
    //TODO: if not in document, use root ancestor instead of document
    let doc = document_from_node(broadcaster).root();
    let radios = doc.QuerySelectorAll("input[type=\"radio\"]".to_string()).unwrap().root();
    let mut i = 0;
    while i < radios.Length() {
        let node = radios.Item(i).unwrap().root();
        let radio: JSRef<HTMLInputElement> = HTMLInputElementCast::to_ref(*node).unwrap();
        if radio != broadcaster {
            //TODO: determine form owner
            let other_group = radio.get_radio_group();
            //TODO: ensure compatibility caseless match (https://html.spec.whatwg.org/multipage/infrastructure.html#compatibility-caseless)
            let group_matches = other_group.as_ref().map(|group| group.as_slice()) == group.as_ref().map(|&group| &*group);
            if group_matches && radio.Checked() {
                radio.SetChecked(false);
            }
        }
        i += 1;
    }
}

impl<'a> HTMLInputElementHelpers for JSRef<'a, HTMLInputElement> {
    fn force_relayout(self) {
        let doc = document_from_node(self).root();
        let node: JSRef<Node> = NodeCast::from_ref(self);
        doc.content_changed(node)
    }

    fn radio_group_updated(self, group: Option<&str>) {
        if self.Checked() {
            broadcast_radio_checked(self, group);
        }
    }

    // https://html.spec.whatwg.org/multipage/forms.html#radio-button-group
    fn get_radio_group(self) -> Option<String> {
        //TODO: determine form owner
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        elem.get_attribute(ns!(""), "name")
            .root()
            .map(|name| name.Value())
    }

    fn update_checked_state(self, checked: bool) {
        self.checked.set(checked);
        if self.input_type.get() == InputRadio && checked {
            broadcast_radio_checked(self,
                                    self.get_radio_group()
                                        .as_ref()
                                        .map(|group| group.as_slice()));
        }
        //TODO: dispatch change event
        self.force_relayout();
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLInputElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        match name.as_slice() {
            "disabled" => {
                node.set_disabled_state(true);
                node.set_enabled_state(false);
            }
            "checked" => {
                self.update_checked_state(true);
            }
            "size" => {
                let parsed = parse_unsigned_integer(value.as_slice().chars());
                self.size.set(parsed.unwrap_or(DEFAULT_INPUT_SIZE));
                self.force_relayout();
            }
            "type" => {
                self.input_type.set(match value.as_slice() {
                    "button" => InputButton(None),
                    "submit" => InputButton(Some(DEFAULT_SUBMIT_VALUE)),
                    "reset" => InputButton(Some(DEFAULT_RESET_VALUE)),
                    "file" => InputFile,
                    "radio" => InputRadio,
                    "checkbox" => InputCheckbox,
                    "password" => InputPassword,
                    _ => InputText,
                });
                if self.input_type.get() == InputRadio {
                    self.radio_group_updated(self.get_radio_group()
                                                 .as_ref()
                                                 .map(|group| group.as_slice()));
                }
                self.force_relayout();
            }
            "value" => {
                *self.value.borrow_mut() = Some(value);
                self.force_relayout();
            }
            "name" => {
                if self.input_type.get() == InputRadio {
                    self.radio_group_updated(Some(value.as_slice()));
                }
            }
            _ => ()
        }
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        match name.as_slice() {
            "disabled" => {
                node.set_disabled_state(false);
                node.set_enabled_state(true);
                node.check_ancestors_disabled_state_for_form_control();
            }
            "checked" => {
                self.update_checked_state(false);
            }
            "size" => {
                self.size.set(DEFAULT_INPUT_SIZE);
                self.force_relayout();
            }
            "type" => {
                if self.input_type.get() == InputRadio {
                    broadcast_radio_checked(*self,
                                            self.get_radio_group()
                                                .as_ref()
                                                .map(|group| group.as_slice()));
                }
                self.input_type.set(InputText);
                self.force_relayout();
            }
            "value" => {
                *self.value.borrow_mut() = None;
                self.force_relayout();
            }
            "name" => {
                if self.input_type.get() == InputRadio {
                    self.radio_group_updated(None);
                }
            }
            _ => ()
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.check_ancestors_disabled_state_for_form_control();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.unbind_from_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        if node.ancestors().any(|ancestor| ancestor.is_htmlfieldsetelement()) {
            node.check_ancestors_disabled_state_for_form_control();
        } else {
            node.check_disabled_attribute();
        }
    }

    fn handle_event(&self, event: JSRef<Event>) {
        match self.super_type() {
            Some(s) => {
                s.handle_event(event);
            }
            _ => (),
        }

        if "click" == event.Type().as_slice() && !event.DefaultPrevented() {
            match self.input_type.get() {
                InputCheckbox => self.SetChecked(!self.checked.get()),
                InputRadio => self.SetChecked(true),
                _ => {}
            }
        }
    }
}

impl Reflectable for HTMLInputElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<commit_msg>Fix <input>.checked<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::Bindings::NodeListBinding::NodeListMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, HTMLInputElementCast, NodeCast};
use dom::bindings::codegen::InheritTypes::{HTMLInputElementDerived, HTMLFieldSetElementDerived};
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, ResultRootable};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::attr::{AttrHelpers};
use dom::document::{Document, DocumentHelpers};
use dom::element::{AttributeHandlers, Element, HTMLInputElementTypeId};
use dom::event::Event;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, document_from_node};
use dom::virtualmethods::VirtualMethods;

use servo_util::str::{DOMString, parse_unsigned_integer};
use string_cache::Atom;

use std::ascii::OwnedStrAsciiExt;
use std::cell::{Cell, RefCell};
use std::mem;

static DEFAULT_SUBMIT_VALUE: &'static str = "Submit";
static DEFAULT_RESET_VALUE: &'static str = "Reset";

#[jstraceable]
#[deriving(PartialEq)]
enum InputType {
    InputButton(Option<&'static str>),
    InputText,
    InputFile,
    InputImage,
    InputCheckbox,
    InputRadio,
    InputPassword
}

#[jstraceable]
#[must_root]
pub struct HTMLInputElement {
    pub htmlelement: HTMLElement,
    input_type: Cell<InputType>,
    checked: Cell<bool>,
    uncommitted_value: RefCell<Option<String>>,
    value: RefCell<Option<String>>,
    size: Cell<u32>,
}

impl HTMLInputElementDerived for EventTarget {
    fn is_htmlinputelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLInputElementTypeId))
    }
}

static DEFAULT_INPUT_SIZE: u32 = 20;

impl HTMLInputElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLInputElement {
        HTMLInputElement {
            htmlelement: HTMLElement::new_inherited(HTMLInputElementTypeId, localName, prefix, document),
            input_type: Cell::new(InputText),
            checked: Cell::new(false),
            uncommitted_value: RefCell::new(None),
            value: RefCell::new(None),
            size: Cell::new(DEFAULT_INPUT_SIZE),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLInputElement> {
        let element = HTMLInputElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLInputElementBinding::Wrap)
    }
}

pub trait LayoutHTMLInputElementHelpers {
    unsafe fn get_value_for_layout(&self) -> String;
    unsafe fn get_size_for_layout(&self) -> u32;
}

impl LayoutHTMLInputElementHelpers for JS<HTMLInputElement> {
    #[allow(unrooted_must_root)]
    unsafe fn get_value_for_layout(&self) -> String {
        unsafe fn get_raw_value(input: &JS<HTMLInputElement>) -> Option<String> {
            mem::transmute::<&RefCell<Option<String>>, &Option<String>>(&(*input.unsafe_get()).value).clone()
        }

        match (*self.unsafe_get()).input_type.get() {
            InputCheckbox | InputRadio => "".to_string(),
            InputFile | InputImage => "".to_string(),
            InputButton(ref default) => get_raw_value(self)
                                          .or_else(|| default.map(|v| v.to_string()))
                                          .unwrap_or_else(|| "".to_string()),
            InputPassword => {
                let raw = get_raw_value(self).unwrap_or_else(|| "".to_string());
                String::from_char(raw.len(), '*')
            }
            _ => get_raw_value(self).unwrap_or_else(|| "".to_string()),
        }
    }

    #[allow(unrooted_must_root)]
    unsafe fn get_size_for_layout(&self) -> u32 {
        (*self.unsafe_get()).size.get()
    }
}

impl<'a> HTMLInputElementMethods for JSRef<'a, HTMLInputElement> {
    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_getter!(Disabled)

    // http://www.whatwg.org/html/#dom-fe-disabled
    make_bool_setter!(SetDisabled, "disabled")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-checked
    fn Checked(self) -> bool {
        self.checked.get()
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-checked
    make_bool_setter!(SetChecked, "checked")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-size
    make_uint_getter!(Size)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-size
    make_uint_setter!(SetSize, "size")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-type
    fn Type(self) -> DOMString {
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        let ty = elem.get_string_attribute("type").into_ascii_lower();
        // https://html.spec.whatwg.org/multipage/forms.html#attr-input-type
        match ty.as_slice() {
            "hidden" | "search" | "tel" |
            "url" | "email" | "password" |
            "datetime" | "date" | "month" |
            "week" | "time" | "datetime-local" |
            "number" | "range" | "color" |
            "checkbox" | "radio" | "file" |
            "submit" | "image" | "reset" | "button" => ty,
            _ => "text".to_string()
        }
    }

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-type
    make_setter!(SetType, "type")

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-value
    make_getter!(Value)

    // https://html.spec.whatwg.org/multipage/forms.html#dom-input-value
    make_setter!(SetValue, "value")

    // https://html.spec.whatwg.org/multipage/forms.html#attr-fe-name
    make_getter!(Name)

    // https://html.spec.whatwg.org/multipage/forms.html#attr-fe-name
    make_setter!(SetName, "name")
}

trait HTMLInputElementHelpers {
    fn force_relayout(self);
    fn radio_group_updated(self, group: Option<&str>);
    fn get_radio_group(self) -> Option<String>;
    fn update_checked_state(self, checked: bool);
}

fn broadcast_radio_checked(broadcaster: JSRef<HTMLInputElement>, group: Option<&str>) {
    //TODO: if not in document, use root ancestor instead of document
    let doc = document_from_node(broadcaster).root();
    let radios = doc.QuerySelectorAll("input[type=\"radio\"]".to_string()).unwrap().root();
    let mut i = 0;
    while i < radios.Length() {
        let node = radios.Item(i).unwrap().root();
        let radio: JSRef<HTMLInputElement> = HTMLInputElementCast::to_ref(*node).unwrap();
        if radio != broadcaster {
            //TODO: determine form owner
            let other_group = radio.get_radio_group();
            //TODO: ensure compatibility caseless match (https://html.spec.whatwg.org/multipage/infrastructure.html#compatibility-caseless)
            let group_matches = other_group.as_ref().map(|group| group.as_slice()) == group.as_ref().map(|&group| &*group);
            if group_matches && radio.Checked() {
                radio.SetChecked(false);
            }
        }
        i += 1;
    }
}

impl<'a> HTMLInputElementHelpers for JSRef<'a, HTMLInputElement> {
    fn force_relayout(self) {
        let doc = document_from_node(self).root();
        let node: JSRef<Node> = NodeCast::from_ref(self);
        doc.content_changed(node)
    }

    fn radio_group_updated(self, group: Option<&str>) {
        if self.Checked() {
            broadcast_radio_checked(self, group);
        }
    }

    // https://html.spec.whatwg.org/multipage/forms.html#radio-button-group
    fn get_radio_group(self) -> Option<String> {
        //TODO: determine form owner
        let elem: JSRef<Element> = ElementCast::from_ref(self);
        elem.get_attribute(ns!(""), "name")
            .root()
            .map(|name| name.Value())
    }

    fn update_checked_state(self, checked: bool) {
        self.checked.set(checked);
        if self.input_type.get() == InputRadio && checked {
            broadcast_radio_checked(self,
                                    self.get_radio_group()
                                        .as_ref()
                                        .map(|group| group.as_slice()));
        }
        //TODO: dispatch change event
        self.force_relayout();
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLInputElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        match name.as_slice() {
            "disabled" => {
                node.set_disabled_state(true);
                node.set_enabled_state(false);
            }
            "checked" => {
                self.update_checked_state(true);
            }
            "size" => {
                let parsed = parse_unsigned_integer(value.as_slice().chars());
                self.size.set(parsed.unwrap_or(DEFAULT_INPUT_SIZE));
                self.force_relayout();
            }
            "type" => {
                self.input_type.set(match value.as_slice() {
                    "button" => InputButton(None),
                    "submit" => InputButton(Some(DEFAULT_SUBMIT_VALUE)),
                    "reset" => InputButton(Some(DEFAULT_RESET_VALUE)),
                    "file" => InputFile,
                    "radio" => InputRadio,
                    "checkbox" => InputCheckbox,
                    "password" => InputPassword,
                    _ => InputText,
                });
                if self.input_type.get() == InputRadio {
                    self.radio_group_updated(self.get_radio_group()
                                                 .as_ref()
                                                 .map(|group| group.as_slice()));
                }
                self.force_relayout();
            }
            "value" => {
                *self.value.borrow_mut() = Some(value);
                self.force_relayout();
            }
            "name" => {
                if self.input_type.get() == InputRadio {
                    self.radio_group_updated(Some(value.as_slice()));
                }
            }
            _ => ()
        }
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        match name.as_slice() {
            "disabled" => {
                node.set_disabled_state(false);
                node.set_enabled_state(true);
                node.check_ancestors_disabled_state_for_form_control();
            }
            "checked" => {
                self.update_checked_state(false);
            }
            "size" => {
                self.size.set(DEFAULT_INPUT_SIZE);
                self.force_relayout();
            }
            "type" => {
                if self.input_type.get() == InputRadio {
                    broadcast_radio_checked(*self,
                                            self.get_radio_group()
                                                .as_ref()
                                                .map(|group| group.as_slice()));
                }
                self.input_type.set(InputText);
                self.force_relayout();
            }
            "value" => {
                *self.value.borrow_mut() = None;
                self.force_relayout();
            }
            "name" => {
                if self.input_type.get() == InputRadio {
                    self.radio_group_updated(None);
                }
            }
            _ => ()
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        node.check_ancestors_disabled_state_for_form_control();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.unbind_from_tree(tree_in_doc),
            _ => (),
        }

        let node: JSRef<Node> = NodeCast::from_ref(*self);
        if node.ancestors().any(|ancestor| ancestor.is_htmlfieldsetelement()) {
            node.check_ancestors_disabled_state_for_form_control();
        } else {
            node.check_disabled_attribute();
        }
    }

    fn handle_event(&self, event: JSRef<Event>) {
        match self.super_type() {
            Some(s) => {
                s.handle_event(event);
            }
            _ => (),
        }

        if "click" == event.Type().as_slice() && !event.DefaultPrevented() {
            match self.input_type.get() {
                InputCheckbox => self.SetChecked(!self.checked.get()),
                InputRadio => self.SetChecked(true),
                _ => {}
            }
        }
    }
}

impl Reflectable for HTMLInputElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<|endoftext|>


<commit_before>mod handlers;
mod subscriptions;

use std::path::PathBuf;

use crossbeam_channel::{unbounded, Receiver, Sender};
use gen_lsp_server::{
    handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse,
};
use languageserver_types::NumberOrString;
use ra_analysis::{FileId, LibraryData};
use rayon::{self, ThreadPool};
use rustc_hash::FxHashSet;
use serde::{de::DeserializeOwned, Serialize};

use crate::{
    main_loop::subscriptions::Subscriptions,
    project_model::{workspace_loader, CargoWorkspace},
    req,
    server_world::{ServerWorld, ServerWorldState},
    thread_watcher::Worker,
    vfs::{self, FileEvent},
    Result,
};

#[derive(Debug)]
enum Task {
    Respond(RawResponse),
    Notify(RawNotification),
}

pub fn main_loop(
    internal_mode: bool,
    root: PathBuf,
    msg_receriver: &Receiver<RawMessage>,
    msg_sender: &Sender<RawMessage>,
) -> Result<()> {
    let pool = rayon::ThreadPoolBuilder::new()
        .num_threads(4)
        .panic_handler(|_| error!("thread panicked :("))
        .build()
        .unwrap();
    let (task_sender, task_receiver) = unbounded::<Task>();
    let (fs_worker, fs_watcher) = vfs::roots_loader();
    let (ws_worker, ws_watcher) = workspace_loader();

    info!("server initialized, serving requests");
    let mut state = ServerWorldState::new();

    let mut pending_requests = FxHashSet::default();
    let mut subs = Subscriptions::new();
    let main_res = main_loop_inner(
        internal_mode,
        root,
        &pool,
        msg_sender,
        msg_receriver,
        task_sender,
        task_receiver.clone(),
        fs_worker,
        ws_worker,
        &mut state,
        &mut pending_requests,
        &mut subs,
    );

    info!("waiting for tasks to finish...");
    task_receiver.for_each(|task| on_task(task, msg_sender, &mut pending_requests));
    info!("...tasks have finished");
    info!("joining threadpool...");
    drop(pool);
    info!("...threadpool has finished");

    let fs_res = fs_watcher.stop();
    let ws_res = ws_watcher.stop();

    main_res?;
    fs_res?;
    ws_res?;

    Ok(())
}

fn main_loop_inner(
    internal_mode: bool,
    ws_root: PathBuf,
    pool: &ThreadPool,
    msg_sender: &Sender<RawMessage>,
    msg_receiver: &Receiver<RawMessage>,
    task_sender: Sender<Task>,
    task_receiver: Receiver<Task>,
    fs_worker: Worker<PathBuf, (PathBuf, Vec<FileEvent>)>,
    ws_worker: Worker<PathBuf, Result<CargoWorkspace>>,
    state: &mut ServerWorldState,
    pending_requests: &mut FxHashSet<u64>,
    subs: &mut Subscriptions,
) -> Result<()> {
    let (libdata_sender, libdata_receiver) = unbounded();
    ws_worker.send(ws_root.clone());
    fs_worker.send(ws_root.clone());
    loop {
        #[derive(Debug)]
        enum Event {
            Msg(RawMessage),
            Task(Task),
            Fs(PathBuf, Vec<FileEvent>),
            Ws(Result<CargoWorkspace>),
            Lib(LibraryData),
        }
        trace!("selecting");
        let event = select! {
            recv(msg_receiver, msg) => match msg {
                Some(msg) => Event::Msg(msg),
                None => bail!("client exited without shutdown"),
            },
            recv(task_receiver, task) => Event::Task(task.unwrap()),
            recv(fs_worker.out, events) => match events {
                None => bail!("roots watcher died"),
                Some((pb, events)) => Event::Fs(pb, events),
            }
            recv(ws_worker.out, ws) => match ws {
                None => bail!("workspace watcher died"),
                Some(ws) => Event::Ws(ws),
            }
            recv(libdata_receiver, data) => Event::Lib(data.unwrap())
        };
        let mut state_changed = false;
        match event {
            Event::Task(task) => on_task(task, msg_sender, pending_requests),
            Event::Fs(root, events) => {
                info!("fs change, {}, {} events", root.display(), events.len());
                if root == ws_root {
                    state.apply_fs_changes(events);
                } else {
                    let (files, resolver) = state.events_to_files(events);
                    let sender = libdata_sender.clone();
                    pool.spawn(move || {
                        let start = ::std::time::Instant::now();
                        info!("indexing {} ... ", root.display());
                        let data = LibraryData::prepare(files, resolver);
                        info!("indexed {:?} {}", start.elapsed(), root.display());
                        sender.send(data);
                    });
                }
                state_changed = true;
            }
            Event::Ws(ws) => match ws {
                Ok(ws) => {
                    let workspaces = vec![ws];
                    feedback(internal_mode, "workspace loaded", msg_sender);
                    for ws in workspaces.iter() {
                        for pkg in ws.packages().filter(|pkg| !pkg.is_member(ws)) {
                            debug!("sending root, {}", pkg.root(ws).to_path_buf().display());
                            fs_worker.send(pkg.root(ws).to_path_buf());
                        }
                    }
                    state.set_workspaces(workspaces);
                    state_changed = true;
                }
                Err(e) => warn!("loading workspace failed: {}", e),
            },
            Event::Lib(lib) => {
                feedback(internal_mode, "library loaded", msg_sender);
                state.add_lib(lib);
            }
            Event::Msg(msg) => match msg {
                RawMessage::Request(req) => {
                    let req = match handle_shutdown(req, msg_sender) {
                        Some(req) => req,
                        None => return Ok(()),
                    };
                    match on_request(state, pending_requests, pool, &task_sender, req)? {
                        None => (),
                        Some(req) => {
                            error!("unknown request: {:?}", req);
                            let resp = RawResponse::err(
                                req.id,
                                ErrorCode::MethodNotFound as i32,
                                "unknown request".to_string(),
                            );
                            msg_sender.send(RawMessage::Response(resp))
                        }
                    }
                }
                RawMessage::Notification(not) => {
                    on_notification(msg_sender, state, pending_requests, subs, not)?;
                    state_changed = true;
                }
                RawMessage::Response(resp) => error!("unexpected response: {:?}", resp),
            },
        };

        if state_changed {
            update_file_notifications_on_threadpool(
                pool,
                state.snapshot(),
                task_sender.clone(),
                subs.subscriptions(),
            )
        }
    }
}

fn on_task(
    task: Task,
    msg_sender: &Sender<RawMessage>,
    pending_requests: &mut FxHashSet<u64>,
) {
    match task {
        Task::Respond(response) => {
            if pending_requests.remove(&response.id) {
                msg_sender.send(RawMessage::Response(response))
            }
        }
        Task::Notify(n) => msg_sender.send(RawMessage::Notification(n)),
    }
}

fn on_request(
    world: &mut ServerWorldState,
    pending_requests: &mut FxHashSet<u64>,
    pool: &ThreadPool,
    sender: &Sender<Task>,
    req: RawRequest,
) -> Result<Option<RawRequest>> {
    let mut pool_dispatcher = PoolDispatcher {
        req: Some(req),
        res: None,
        pool,
        world,
        sender,
    };
    let req = pool_dispatcher
        .on::<req::SyntaxTree>(handlers::handle_syntax_tree)?
        .on::<req::ExtendSelection>(handlers::handle_extend_selection)?
        .on::<req::FindMatchingBrace>(handlers::handle_find_matching_brace)?
        .on::<req::JoinLines>(handlers::handle_join_lines)?
        .on::<req::OnEnter>(handlers::handle_on_enter)?
        .on::<req::OnTypeFormatting>(handlers::handle_on_type_formatting)?
        .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)?
        .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)?
        .on::<req::GotoDefinition>(handlers::handle_goto_definition)?
        .on::<req::ParentModule>(handlers::handle_parent_module)?
        .on::<req::Runnables>(handlers::handle_runnables)?
        .on::<req::DecorationsRequest>(handlers::handle_decorations)?
        .on::<req::Completion>(handlers::handle_completion)?
        .on::<req::CodeActionRequest>(handlers::handle_code_action)?
        .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
        .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
        .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
        .on::<req::Rename>(handlers::handle_rename)?
        .on::<req::References>(handlers::handle_references)?
        .finish();
    match req {
        Ok(id) => {
            let inserted = pending_requests.insert(id);
            assert!(inserted, "duplicate request: {}", id);
            Ok(None)
        }
        Err(req) => Ok(Some(req)),
    }
}

fn on_notification(
    msg_sender: &Sender<RawMessage>,
    state: &mut ServerWorldState,
    pending_requests: &mut FxHashSet<u64>,
    subs: &mut Subscriptions,
    not: RawNotification,
) -> Result<()> {
    let not = match not.cast::<req::Cancel>() {
        Ok(params) => {
            let id = match params.id {
                NumberOrString::Number(id) => id,
                NumberOrString::String(id) => {
                    panic!("string id's not supported: {:?}", id);
                }
            };
            pending_requests.remove(&id);
            return Ok(());
        }
        Err(not) => not,
    };
    let not = match not.cast::<req::DidOpenTextDocument>() {
        Ok(params) => {
            let uri = params.text_document.uri;
            let path = uri
                .to_file_path()
                .map_err(|()| format_err!("invalid uri: {}", uri))?;
            let file_id = state.add_mem_file(path, params.text_document.text);
            subs.add_sub(file_id);
            return Ok(());
        }
        Err(not) => not,
    };
    let not = match not.cast::<req::DidChangeTextDocument>() {
        Ok(mut params) => {
            let uri = params.text_document.uri;
            let path = uri
                .to_file_path()
                .map_err(|()| format_err!("invalid uri: {}", uri))?;
            let text = params
                .content_changes
                .pop()
                .ok_or_else(|| format_err!("empty changes"))?
                .text;
            state.change_mem_file(path.as_path(), text)?;
            return Ok(());
        }
        Err(not) => not,
    };
    let not = match not.cast::<req::DidCloseTextDocument>() {
        Ok(params) => {
            let uri = params.text_document.uri;
            let path = uri
                .to_file_path()
                .map_err(|()| format_err!("invalid uri: {}", uri))?;
            let file_id = state.remove_mem_file(path.as_path())?;
            subs.remove_sub(file_id);
            let params = req::PublishDiagnosticsParams {
                uri,
                diagnostics: Vec::new(),
            };
            let not = RawNotification::new::<req::PublishDiagnostics>(&params);
            msg_sender.send(RawMessage::Notification(not));
            return Ok(());
        }
        Err(not) => not,
    };
    error!("unhandled notification: {:?}", not);
    Ok(())
}

struct PoolDispatcher<'a> {
    req: Option<RawRequest>,
    res: Option<u64>,
    pool: &'a ThreadPool,
    world: &'a ServerWorldState,
    sender: &'a Sender<Task>,
}

impl<'a> PoolDispatcher<'a> {
    fn on<'b, R>(
        &'b mut self,
        f: fn(ServerWorld, R::Params) -> Result<R::Result>,
    ) -> Result<&'b mut Self>
    where
        R: req::Request,
        R::Params: DeserializeOwned + Send + 'static,
        R::Result: Serialize + 'static,
    {
        let req = match self.req.take() {
            None => return Ok(self),
            Some(req) => req,
        };
        match req.cast::<R>() {
            Ok((id, params)) => {
                let world = self.world.snapshot();
                let sender = self.sender.clone();
                self.pool.spawn(move || {
                    let resp = match f(world, params) {
                        Ok(resp) => RawResponse::ok::<R>(id, &resp),
                        Err(e) => {
                            RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string())
                        }
                    };
                    let task = Task::Respond(resp);
                    sender.send(task);
                });
                self.res = Some(id);
            }
            Err(req) => self.req = Some(req),
        }
        Ok(self)
    }

    fn finish(&mut self) -> ::std::result::Result<u64, RawRequest> {
        match (self.res.take(), self.req.take()) {
            (Some(res), None) => Ok(res),
            (None, Some(req)) => Err(req),
            _ => unreachable!(),
        }
    }
}

fn update_file_notifications_on_threadpool(
    pool: &ThreadPool,
    world: ServerWorld,
    sender: Sender<Task>,
    subscriptions: Vec<FileId>,
) {
    pool.spawn(move || {
        for file_id in subscriptions {
            match handlers::publish_diagnostics(&world, file_id) {
                Err(e) => error!("failed to compute diagnostics: {:?}", e),
                Ok(params) => {
                    let not = RawNotification::new::<req::PublishDiagnostics>(&params);
                    sender.send(Task::Notify(not));
                }
            }
            match handlers::publish_decorations(&world, file_id) {
                Err(e) => error!("failed to compute decorations: {:?}", e),
                Ok(params) => {
                    let not = RawNotification::new::<req::PublishDecorations>(&params);
                    sender.send(Task::Notify(not))
                }
            }
        }
    });
}

fn feedback(intrnal_mode: bool, msg: &str, sender: &Sender<RawMessage>) {
    if !intrnal_mode {
        return;
    }
    let not = RawNotification::new::<req::InternalFeedback>(&msg.to_string());
    sender.send(RawMessage::Notification(not));
}
<commit_msg>Fix typo<commit_after>mod handlers;
mod subscriptions;

use std::path::PathBuf;

use crossbeam_channel::{unbounded, Receiver, Sender};
use gen_lsp_server::{
    handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse,
};
use languageserver_types::NumberOrString;
use ra_analysis::{FileId, LibraryData};
use rayon::{self, ThreadPool};
use rustc_hash::FxHashSet;
use serde::{de::DeserializeOwned, Serialize};

use crate::{
    main_loop::subscriptions::Subscriptions,
    project_model::{workspace_loader, CargoWorkspace},
    req,
    server_world::{ServerWorld, ServerWorldState},
    thread_watcher::Worker,
    vfs::{self, FileEvent},
    Result,
};

#[derive(Debug)]
enum Task {
    Respond(RawResponse),
    Notify(RawNotification),
}

pub fn main_loop(
    internal_mode: bool,
    root: PathBuf,
    msg_receiver: &Receiver<RawMessage>,
    msg_sender: &Sender<RawMessage>,
) -> Result<()> {
    let pool = rayon::ThreadPoolBuilder::new()
        .num_threads(4)
        .panic_handler(|_| error!("thread panicked :("))
        .build()
        .unwrap();
    let (task_sender, task_receiver) = unbounded::<Task>();
    let (fs_worker, fs_watcher) = vfs::roots_loader();
    let (ws_worker, ws_watcher) = workspace_loader();

    info!("server initialized, serving requests");
    let mut state = ServerWorldState::new();

    let mut pending_requests = FxHashSet::default();
    let mut subs = Subscriptions::new();
    let main_res = main_loop_inner(
        internal_mode,
        root,
        &pool,
        msg_sender,
        msg_receiver,
        task_sender,
        task_receiver.clone(),
        fs_worker,
        ws_worker,
        &mut state,
        &mut pending_requests,
        &mut subs,
    );

    info!("waiting for tasks to finish...");
    task_receiver.for_each(|task| on_task(task, msg_sender, &mut pending_requests));
    info!("...tasks have finished");
    info!("joining threadpool...");
    drop(pool);
    info!("...threadpool has finished");

    let fs_res = fs_watcher.stop();
    let ws_res = ws_watcher.stop();

    main_res?;
    fs_res?;
    ws_res?;

    Ok(())
}

fn main_loop_inner(
    internal_mode: bool,
    ws_root: PathBuf,
    pool: &ThreadPool,
    msg_sender: &Sender<RawMessage>,
    msg_receiver: &Receiver<RawMessage>,
    task_sender: Sender<Task>,
    task_receiver: Receiver<Task>,
    fs_worker: Worker<PathBuf, (PathBuf, Vec<FileEvent>)>,
    ws_worker: Worker<PathBuf, Result<CargoWorkspace>>,
    state: &mut ServerWorldState,
    pending_requests: &mut FxHashSet<u64>,
    subs: &mut Subscriptions,
) -> Result<()> {
    let (libdata_sender, libdata_receiver) = unbounded();
    ws_worker.send(ws_root.clone());
    fs_worker.send(ws_root.clone());
    loop {
        #[derive(Debug)]
        enum Event {
            Msg(RawMessage),
            Task(Task),
            Fs(PathBuf, Vec<FileEvent>),
            Ws(Result<CargoWorkspace>),
            Lib(LibraryData),
        }
        trace!("selecting");
        let event = select! {
            recv(msg_receiver, msg) => match msg {
                Some(msg) => Event::Msg(msg),
                None => bail!("client exited without shutdown"),
            },
            recv(task_receiver, task) => Event::Task(task.unwrap()),
            recv(fs_worker.out, events) => match events {
                None => bail!("roots watcher died"),
                Some((pb, events)) => Event::Fs(pb, events),
            }
            recv(ws_worker.out, ws) => match ws {
                None => bail!("workspace watcher died"),
                Some(ws) => Event::Ws(ws),
            }
            recv(libdata_receiver, data) => Event::Lib(data.unwrap())
        };
        let mut state_changed = false;
        match event {
            Event::Task(task) => on_task(task, msg_sender, pending_requests),
            Event::Fs(root, events) => {
                info!("fs change, {}, {} events", root.display(), events.len());
                if root == ws_root {
                    state.apply_fs_changes(events);
                } else {
                    let (files, resolver) = state.events_to_files(events);
                    let sender = libdata_sender.clone();
                    pool.spawn(move || {
                        let start = ::std::time::Instant::now();
                        info!("indexing {} ... ", root.display());
                        let data = LibraryData::prepare(files, resolver);
                        info!("indexed {:?} {}", start.elapsed(), root.display());
                        sender.send(data);
                    });
                }
                state_changed = true;
            }
            Event::Ws(ws) => match ws {
                Ok(ws) => {
                    let workspaces = vec![ws];
                    feedback(internal_mode, "workspace loaded", msg_sender);
                    for ws in workspaces.iter() {
                        for pkg in ws.packages().filter(|pkg| !pkg.is_member(ws)) {
                            debug!("sending root, {}", pkg.root(ws).to_path_buf().display());
                            fs_worker.send(pkg.root(ws).to_path_buf());
                        }
                    }
                    state.set_workspaces(workspaces);
                    state_changed = true;
                }
                Err(e) => warn!("loading workspace failed: {}", e),
            },
            Event::Lib(lib) => {
                feedback(internal_mode, "library loaded", msg_sender);
                state.add_lib(lib);
            }
            Event::Msg(msg) => match msg {
                RawMessage::Request(req) => {
                    let req = match handle_shutdown(req, msg_sender) {
                        Some(req) => req,
                        None => return Ok(()),
                    };
                    match on_request(state, pending_requests, pool, &task_sender, req)? {
                        None => (),
                        Some(req) => {
                            error!("unknown request: {:?}", req);
                            let resp = RawResponse::err(
                                req.id,
                                ErrorCode::MethodNotFound as i32,
                                "unknown request".to_string(),
                            );
                            msg_sender.send(RawMessage::Response(resp))
                        }
                    }
                }
                RawMessage::Notification(not) => {
                    on_notification(msg_sender, state, pending_requests, subs, not)?;
                    state_changed = true;
                }
                RawMessage::Response(resp) => error!("unexpected response: {:?}", resp),
            },
        };

        if state_changed {
            update_file_notifications_on_threadpool(
                pool,
                state.snapshot(),
                task_sender.clone(),
                subs.subscriptions(),
            )
        }
    }
}

fn on_task(
    task: Task,
    msg_sender: &Sender<RawMessage>,
    pending_requests: &mut FxHashSet<u64>,
) {
    match task {
        Task::Respond(response) => {
            if pending_requests.remove(&response.id) {
                msg_sender.send(RawMessage::Response(response))
            }
        }
        Task::Notify(n) => msg_sender.send(RawMessage::Notification(n)),
    }
}

fn on_request(
    world: &mut ServerWorldState,
    pending_requests: &mut FxHashSet<u64>,
    pool: &ThreadPool,
    sender: &Sender<Task>,
    req: RawRequest,
) -> Result<Option<RawRequest>> {
    let mut pool_dispatcher = PoolDispatcher {
        req: Some(req),
        res: None,
        pool,
        world,
        sender,
    };
    let req = pool_dispatcher
        .on::<req::SyntaxTree>(handlers::handle_syntax_tree)?
        .on::<req::ExtendSelection>(handlers::handle_extend_selection)?
        .on::<req::FindMatchingBrace>(handlers::handle_find_matching_brace)?
        .on::<req::JoinLines>(handlers::handle_join_lines)?
        .on::<req::OnEnter>(handlers::handle_on_enter)?
        .on::<req::OnTypeFormatting>(handlers::handle_on_type_formatting)?
        .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)?
        .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)?
        .on::<req::GotoDefinition>(handlers::handle_goto_definition)?
        .on::<req::ParentModule>(handlers::handle_parent_module)?
        .on::<req::Runnables>(handlers::handle_runnables)?
        .on::<req::DecorationsRequest>(handlers::handle_decorations)?
        .on::<req::Completion>(handlers::handle_completion)?
        .on::<req::CodeActionRequest>(handlers::handle_code_action)?
        .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
        .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
        .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
        .on::<req::Rename>(handlers::handle_rename)?
        .on::<req::References>(handlers::handle_references)?
        .finish();
    match req {
        Ok(id) => {
            let inserted = pending_requests.insert(id);
            assert!(inserted, "duplicate request: {}", id);
            Ok(None)
        }
        Err(req) => Ok(Some(req)),
    }
}

fn on_notification(
    msg_sender: &Sender<RawMessage>,
    state: &mut ServerWorldState,
    pending_requests: &mut FxHashSet<u64>,
    subs: &mut Subscriptions,
    not: RawNotification,
) -> Result<()> {
    let not = match not.cast::<req::Cancel>() {
        Ok(params) => {
            let id = match params.id {
                NumberOrString::Number(id) => id,
                NumberOrString::String(id) => {
                    panic!("string id's not supported: {:?}", id);
                }
            };
            pending_requests.remove(&id);
            return Ok(());
        }
        Err(not) => not,
    };
    let not = match not.cast::<req::DidOpenTextDocument>() {
        Ok(params) => {
            let uri = params.text_document.uri;
            let path = uri
                .to_file_path()
                .map_err(|()| format_err!("invalid uri: {}", uri))?;
            let file_id = state.add_mem_file(path, params.text_document.text);
            subs.add_sub(file_id);
            return Ok(());
        }
        Err(not) => not,
    };
    let not = match not.cast::<req::DidChangeTextDocument>() {
        Ok(mut params) => {
            let uri = params.text_document.uri;
            let path = uri
                .to_file_path()
                .map_err(|()| format_err!("invalid uri: {}", uri))?;
            let text = params
                .content_changes
                .pop()
                .ok_or_else(|| format_err!("empty changes"))?
                .text;
            state.change_mem_file(path.as_path(), text)?;
            return Ok(());
        }
        Err(not) => not,
    };
    let not = match not.cast::<req::DidCloseTextDocument>() {
        Ok(params) => {
            let uri = params.text_document.uri;
            let path = uri
                .to_file_path()
                .map_err(|()| format_err!("invalid uri: {}", uri))?;
            let file_id = state.remove_mem_file(path.as_path())?;
            subs.remove_sub(file_id);
            let params = req::PublishDiagnosticsParams {
                uri,
                diagnostics: Vec::new(),
            };
            let not = RawNotification::new::<req::PublishDiagnostics>(&params);
            msg_sender.send(RawMessage::Notification(not));
            return Ok(());
        }
        Err(not) => not,
    };
    error!("unhandled notification: {:?}", not);
    Ok(())
}

struct PoolDispatcher<'a> {
    req: Option<RawRequest>,
    res: Option<u64>,
    pool: &'a ThreadPool,
    world: &'a ServerWorldState,
    sender: &'a Sender<Task>,
}

impl<'a> PoolDispatcher<'a> {
    fn on<'b, R>(
        &'b mut self,
        f: fn(ServerWorld, R::Params) -> Result<R::Result>,
    ) -> Result<&'b mut Self>
    where
        R: req::Request,
        R::Params: DeserializeOwned + Send + 'static,
        R::Result: Serialize + 'static,
    {
        let req = match self.req.take() {
            None => return Ok(self),
            Some(req) => req,
        };
        match req.cast::<R>() {
            Ok((id, params)) => {
                let world = self.world.snapshot();
                let sender = self.sender.clone();
                self.pool.spawn(move || {
                    let resp = match f(world, params) {
                        Ok(resp) => RawResponse::ok::<R>(id, &resp),
                        Err(e) => {
                            RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string())
                        }
                    };
                    let task = Task::Respond(resp);
                    sender.send(task);
                });
                self.res = Some(id);
            }
            Err(req) => self.req = Some(req),
        }
        Ok(self)
    }

    fn finish(&mut self) -> ::std::result::Result<u64, RawRequest> {
        match (self.res.take(), self.req.take()) {
            (Some(res), None) => Ok(res),
            (None, Some(req)) => Err(req),
            _ => unreachable!(),
        }
    }
}

fn update_file_notifications_on_threadpool(
    pool: &ThreadPool,
    world: ServerWorld,
    sender: Sender<Task>,
    subscriptions: Vec<FileId>,
) {
    pool.spawn(move || {
        for file_id in subscriptions {
            match handlers::publish_diagnostics(&world, file_id) {
                Err(e) => error!("failed to compute diagnostics: {:?}", e),
                Ok(params) => {
                    let not = RawNotification::new::<req::PublishDiagnostics>(&params);
                    sender.send(Task::Notify(not));
                }
            }
            match handlers::publish_decorations(&world, file_id) {
                Err(e) => error!("failed to compute decorations: {:?}", e),
                Ok(params) => {
                    let not = RawNotification::new::<req::PublishDecorations>(&params);
                    sender.send(Task::Notify(not))
                }
            }
        }
    });
}

fn feedback(intrnal_mode: bool, msg: &str, sender: &Sender<RawMessage>) {
    if !intrnal_mode {
        return;
    }
    let not = RawNotification::new::<req::InternalFeedback>(&msg.to_string());
    sender.send(RawMessage::Notification(not));
}
<|endoftext|>


<commit_before>generate_result_logging_extension!(
    WarnResult,
    map_warn,
    map_warn_str,
    map_warn_err,
    map_warn_err_str,
    |s| { warn!("{}", s); }
);

<commit_msg>Add comment for warn_result code<commit_after>// Generates a extension for the `Result<T, E>`, named `DebugResult` which has functionality to
// print either `T` or `E` via `warn!()`.
generate_result_logging_extension!(
    WarnResult,
    map_warn,
    map_warn_str,
    map_warn_err,
    map_warn_err_str,
    |s| { warn!("{}", s); }
);

<|endoftext|>