<commit_before>use crate::codec::*;
use crate::error::*;
use crate::*;
use crate::{SocketType, ZmqResult};
use async_trait::async_trait;
use crossbeam::queue::SegQueue;
use dashmap::DashMap;
use futures::lock::Mutex;
use futures::stream::FuturesUnordered;
use futures_util::sink::SinkExt;
use std::sync::Arc;
use std::time::Duration;
use tokio::stream::StreamExt;

struct ReqSocketBackend {
    pub(crate) peers: Arc<DashMap<PeerIdentity, Peer>>,
    pub(crate) round_robin: SegQueue<PeerIdentity>,
}

pub struct ReqSocket {
    backend: Arc<ReqSocketBackend>,
    _accept_close_handle: Option<oneshot::Sender<bool>>,
    current_request: Option<PeerIdentity>,
}

#[async_trait]
impl BlockingSend for ReqSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        if self.current_request.is_some() {
            return Err(ZmqError::Socket(
                "Unable to send message. Request already in progress",
            ));
        }
        // In normal scenario this will always be only 1 iteration
        // There can be special case when peer has disconnected and his id is still in RR queue
        // This happens because SegQueue don't have an api to delete items from queue.
        // So in such case we'll just pop item and skip it if we don't have a matching peer in peers map
        loop {
            let next_peer_id = match self.backend.round_robin.pop() {
                Ok(peer) => peer,
                Err(_) => {
                    return Err(ZmqError::Other(
                        "Not connected to peers. Unable to send messages",
                    ))
                }
            };
            match self.backend.peers.get_mut(&next_peer_id) {
                Some(mut peer) => {
                    let frames = vec![
                        "".into(), // delimiter frame
                        message,
                    ];
                    peer.send_queue
                        .send(Message::MultipartMessage(frames))
                        .await?;
                    self.current_request = Some(peer.identity.clone());
                    self.backend.round_robin.push(next_peer_id);
                    return Ok(());
                }
                None => continue,
            }
        }
    }
}

#[async_trait]
impl BlockingRecv for ReqSocket {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage> {
        match self.current_request.take() {
            Some(peer_id) => {
                if let Some(recv_queue) = self
                    .backend
                    .peers
                    .get(&peer_id)
                    .map(|p| p.recv_queue.clone())
                {
                    let message = recv_queue.lock().await.next().await;
                    match message {
                        Some(Message::MultipartMessage(mut message)) => {
                            assert!(message.len() == 2);
                            assert!(message[0].data.is_empty()); // Ensure that we have delimeter as first part
                            Ok(message.pop().unwrap())
                        }
                        Some(_) => Err(ZmqError::Other("Wrong message type received")),
                        None => Err(ZmqError::NoMessage),
                    }
                } else {
                    Err(ZmqError::Other("Server disconnected"))
                }
            }
            None => Err(ZmqError::Other("Unable to recv. No request in progress")),
        }
    }
}

#[async_trait]
impl SocketFrontend for ReqSocket {
    fn new() -> Self {
        Self {
            backend: Arc::new(ReqSocketBackend {
                peers: Arc::new(DashMap::new()),
                round_robin: SegQueue::new(),
            }),
            _accept_close_handle: None,
            current_request: None,
        }
    }

    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()> {
        let stop_handle = util::start_accepting_connections(endpoint, self.backend.clone()).await?;
        self._accept_close_handle = Some(stop_handle);
        Ok(())
    }

    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()> {
        let addr = endpoint.parse::<SocketAddr>()?;
        let raw_socket = tokio::net::TcpStream::connect(addr).await?;
        util::peer_connected(raw_socket, self.backend.clone()).await;
        Ok(())
    }
}

impl MultiPeer for ReqSocketBackend {
    fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>) {
        let default_queue_size = 100;
        let (out_queue, out_queue_receiver) = mpsc::channel(default_queue_size);
        let (in_queue, in_queue_receiver) = mpsc::channel(default_queue_size);
        let (stop_handle, stop_callback) = oneshot::channel::<bool>();

        self.peers.insert(
            peer_id.clone(),
            Peer {
                identity: peer_id.clone(),
                send_queue: out_queue,
                recv_queue: Arc::new(Mutex::new(in_queue_receiver)),
                recv_queue_in: in_queue,
                _io_close_handle: stop_handle,
            },
        );
        self.round_robin.push(peer_id.clone());

        (out_queue_receiver, stop_callback)
    }

    fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        self.peers.remove(peer_id);
    }
}

#[async_trait]
impl SocketBackend for ReqSocketBackend {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        self.peers
            .get_mut(peer_id)
            .expect("Not found peer by id")
            .recv_queue_in
            .send(message)
            .await
            .expect("Failed to send");
    }

    fn socket_type(&self) -> SocketType {
        SocketType::REQ
    }

    fn shutdown(&self) {
        self.peers.clear();
    }
}

struct RepSocketBackend {
    pub(crate) peers: Arc<DashMap<PeerIdentity, Peer>>,
}

pub struct RepSocket {
    backend: Arc<RepSocketBackend>,
    _accept_close_handle: Option<oneshot::Sender<bool>>,
    current_request: Option<PeerIdentity>,
}

#[async_trait]
impl SocketFrontend for RepSocket {
    fn new() -> Self {
        Self {
            backend: Arc::new(RepSocketBackend {
                peers: Arc::new(DashMap::new()),
            }),
            _accept_close_handle: None,
            current_request: None,
        }
    }

    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()> {
        let stop_handle = util::start_accepting_connections(endpoint, self.backend.clone()).await?;
        self._accept_close_handle = Some(stop_handle);
        Ok(())
    }

    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()> {
        unimplemented!()
    }
}

impl MultiPeer for RepSocketBackend {
    fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>) {
        let default_queue_size = 100;
        let (out_queue, out_queue_receiver) = mpsc::channel(default_queue_size);
        let (in_queue, in_queue_receiver) = mpsc::channel(default_queue_size);
        let (stop_handle, stop_callback) = oneshot::channel::<bool>();

        self.peers.insert(
            peer_id.clone(),
            Peer {
                identity: peer_id.clone(),
                send_queue: out_queue,
                recv_queue: Arc::new(Mutex::new(in_queue_receiver)),
                recv_queue_in: in_queue,
                _io_close_handle: stop_handle,
            },
        );

        (out_queue_receiver, stop_callback)
    }

    fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        self.peers.remove(peer_id);
    }
}

#[async_trait]
impl SocketBackend for RepSocketBackend {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        self.peers
            .get_mut(peer_id)
            .expect("Not found peer by id")
            .recv_queue_in
            .send(message)
            .await
            .expect("Failed to send");
    }

    fn socket_type(&self) -> SocketType {
        SocketType::REP
    }

    fn shutdown(&self) {
        self.peers.clear();
    }
}

#[async_trait]
impl BlockingSend for RepSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        match self.current_request.take() {
            Some(peer_id) => {
                if let Some(mut peer) = self.backend.peers.get_mut(&peer_id) {
                    let frames = vec![
                        "".into(), // delimiter frame
                        message,
                    ];
                    peer.send_queue
                        .send(Message::MultipartMessage(frames))
                        .await?;
                    Ok(())
                } else {
                    Err(ZmqError::Other("Client disconnected"))
                }
            }
            None => Err(ZmqError::Other(
                "Unable to send reply. No request in progress",
            )),
        }
    }
}

#[async_trait]
impl BlockingRecv for RepSocket {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage> {
        let mut messages = FuturesUnordered::new();
        loop {
            for peer in self.backend.peers.iter() {
                let peer_id = peer.identity.clone();
                let recv_queue = peer.recv_queue.clone();
                messages.push(async move { (peer_id, recv_queue.lock().await.next().await) });
            }

            if messages.is_empty() {
                // TODO this is super stupid way of waiting for new connections
                // Needs to be refactored
                tokio::time::delay_for(Duration::from_millis(100)).await;
                continue;
            } else {
                break;
            }
        }
        loop {
            match messages.next().await {
                Some((peer_id, Some(Message::MultipartMessage(mut messages)))) => {
                    assert!(messages.len() == 2);
                    assert!(messages[0].data.is_empty()); // Ensure that we have delimeter as first part
                    self.current_request = Some(peer_id);
                    return Ok(messages.pop().unwrap());
                }
                Some((peer_id, None)) => {
                    println!("Peer disconnected {:?}", peer_id);
                    self.backend.peers.remove(&peer_id);
                }
                Some((_peer_id, _)) => todo!(),
                None => continue,
            };
        }
    }
}
<commit_msg>Silently discard messages from other peers<commit_after>use crate::codec::*;
use crate::error::*;
use crate::*;
use crate::{SocketType, ZmqResult};
use async_trait::async_trait;
use crossbeam::atomic::AtomicCell;
use crossbeam::queue::SegQueue;
use dashmap::DashMap;
use futures::lock::Mutex;
use futures::stream::FuturesUnordered;
use futures_util::sink::SinkExt;
use std::sync::Arc;
use std::time::Duration;
use tokio::stream::StreamExt;

struct ReqSocketBackend {
    pub(crate) peers: Arc<DashMap<PeerIdentity, Peer>>,
    pub(crate) round_robin: SegQueue<PeerIdentity>,
    pub(crate) current_request_peer_id: AtomicCell<usize>,
}

pub struct ReqSocket {
    backend: Arc<ReqSocketBackend>,
    _accept_close_handle: Option<oneshot::Sender<bool>>,
    current_request: Option<PeerIdentity>,
}

#[async_trait]
impl BlockingSend for ReqSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        if self.current_request.is_some() {
            return Err(ZmqError::Socket(
                "Unable to send message. Request already in progress",
            ));
        }
        // In normal scenario this will always be only 1 iteration
        // There can be special case when peer has disconnected and his id is still in RR queue
        // This happens because SegQueue don't have an api to delete items from queue.
        // So in such case we'll just pop item and skip it if we don't have a matching peer in peers map
        loop {
            let next_peer_id = match self.backend.round_robin.pop() {
                Ok(peer) => peer,
                Err(_) => {
                    return Err(ZmqError::Other(
                        "Not connected to peers. Unable to send messages",
                    ))
                }
            };
            match self.backend.peers.get_mut(&next_peer_id) {
                Some(mut peer) => {
                    let frames = vec![
                        "".into(), // delimiter frame
                        message,
                    ];
                    peer.send_queue
                        .send(Message::MultipartMessage(frames))
                        .await?;
                    self.current_request = Some(next_peer_id.clone());
                    self.backend
                        .current_request_peer_id
                        .store(self.backend.peers.hash_usize(&next_peer_id));
                    self.backend.round_robin.push(next_peer_id);
                    return Ok(());
                }
                None => continue,
            }
        }
    }
}

#[async_trait]
impl BlockingRecv for ReqSocket {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage> {
        match self.current_request.take() {
            Some(peer_id) => {
                if let Some(recv_queue) = self
                    .backend
                    .peers
                    .get(&peer_id)
                    .map(|p| p.recv_queue.clone())
                {
                    let message = recv_queue.lock().await.next().await;
                    match message {
                        Some(Message::MultipartMessage(mut message)) => {
                            assert!(message.len() == 2);
                            assert!(message[0].data.is_empty()); // Ensure that we have delimeter as first part
                            Ok(message.pop().unwrap())
                        }
                        Some(_) => Err(ZmqError::Other("Wrong message type received")),
                        None => Err(ZmqError::NoMessage),
                    }
                } else {
                    Err(ZmqError::Other("Server disconnected"))
                }
            }
            None => Err(ZmqError::Other("Unable to recv. No request in progress")),
        }
    }
}

#[async_trait]
impl SocketFrontend for ReqSocket {
    fn new() -> Self {
        Self {
            backend: Arc::new(ReqSocketBackend {
                peers: Arc::new(DashMap::new()),
                round_robin: SegQueue::new(),
                current_request_peer_id: AtomicCell::new(0),
            }),
            _accept_close_handle: None,
            current_request: None,
        }
    }

    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()> {
        let stop_handle = util::start_accepting_connections(endpoint, self.backend.clone()).await?;
        self._accept_close_handle = Some(stop_handle);
        Ok(())
    }

    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()> {
        let addr = endpoint.parse::<SocketAddr>()?;
        let raw_socket = tokio::net::TcpStream::connect(addr).await?;
        util::peer_connected(raw_socket, self.backend.clone()).await;
        Ok(())
    }
}

impl MultiPeer for ReqSocketBackend {
    fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>) {
        let default_queue_size = 100;
        let (out_queue, out_queue_receiver) = mpsc::channel(default_queue_size);
        let (in_queue, in_queue_receiver) = mpsc::channel(default_queue_size);
        let (stop_handle, stop_callback) = oneshot::channel::<bool>();

        self.peers.insert(
            peer_id.clone(),
            Peer {
                identity: peer_id.clone(),
                send_queue: out_queue,
                recv_queue: Arc::new(Mutex::new(in_queue_receiver)),
                recv_queue_in: in_queue,
                _io_close_handle: stop_handle,
            },
        );
        self.round_robin.push(peer_id.clone());

        (out_queue_receiver, stop_callback)
    }

    fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        self.peers.remove(peer_id);
    }
}

#[async_trait]
impl SocketBackend for ReqSocketBackend {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        let hash = self.peers.hash_usize(&peer_id);
        let current = self.current_request_peer_id.compare_and_swap(hash, 0);
        // This is needed to ensure that we only store messages that we are expecting to get
        // Other messages are silently discarded according to spec
        if current == hash {
            // We've got reply that we were waiting for
            self.peers
                .get_mut(peer_id)
                .expect("Not found peer by id")
                .recv_queue_in
                .send(message)
                .await
                .expect("Failed to send");
        }
    }

    fn socket_type(&self) -> SocketType {
        SocketType::REQ
    }

    fn shutdown(&self) {
        self.peers.clear();
    }
}

struct RepSocketBackend {
    pub(crate) peers: Arc<DashMap<PeerIdentity, Peer>>,
}

pub struct RepSocket {
    backend: Arc<RepSocketBackend>,
    _accept_close_handle: Option<oneshot::Sender<bool>>,
    current_request: Option<PeerIdentity>,
}

#[async_trait]
impl SocketFrontend for RepSocket {
    fn new() -> Self {
        Self {
            backend: Arc::new(RepSocketBackend {
                peers: Arc::new(DashMap::new()),
            }),
            _accept_close_handle: None,
            current_request: None,
        }
    }

    async fn bind(&mut self, endpoint: &str) -> ZmqResult<()> {
        let stop_handle = util::start_accepting_connections(endpoint, self.backend.clone()).await?;
        self._accept_close_handle = Some(stop_handle);
        Ok(())
    }

    async fn connect(&mut self, endpoint: &str) -> ZmqResult<()> {
        unimplemented!()
    }
}

impl MultiPeer for RepSocketBackend {
    fn peer_connected(
        &self,
        peer_id: &PeerIdentity,
    ) -> (mpsc::Receiver<Message>, oneshot::Receiver<bool>) {
        let default_queue_size = 100;
        let (out_queue, out_queue_receiver) = mpsc::channel(default_queue_size);
        let (in_queue, in_queue_receiver) = mpsc::channel(default_queue_size);
        let (stop_handle, stop_callback) = oneshot::channel::<bool>();

        self.peers.insert(
            peer_id.clone(),
            Peer {
                identity: peer_id.clone(),
                send_queue: out_queue,
                recv_queue: Arc::new(Mutex::new(in_queue_receiver)),
                recv_queue_in: in_queue,
                _io_close_handle: stop_handle,
            },
        );

        (out_queue_receiver, stop_callback)
    }

    fn peer_disconnected(&self, peer_id: &PeerIdentity) {
        self.peers.remove(peer_id);
    }
}

#[async_trait]
impl SocketBackend for RepSocketBackend {
    async fn message_received(&self, peer_id: &PeerIdentity, message: Message) {
        self.peers
            .get_mut(peer_id)
            .expect("Not found peer by id")
            .recv_queue_in
            .send(message)
            .await
            .expect("Failed to send");
    }

    fn socket_type(&self) -> SocketType {
        SocketType::REP
    }

    fn shutdown(&self) {
        self.peers.clear();
    }
}

#[async_trait]
impl BlockingSend for RepSocket {
    async fn send(&mut self, message: ZmqMessage) -> ZmqResult<()> {
        match self.current_request.take() {
            Some(peer_id) => {
                if let Some(mut peer) = self.backend.peers.get_mut(&peer_id) {
                    let frames = vec![
                        "".into(), // delimiter frame
                        message,
                    ];
                    peer.send_queue
                        .send(Message::MultipartMessage(frames))
                        .await?;
                    Ok(())
                } else {
                    Err(ZmqError::Other("Client disconnected"))
                }
            }
            None => Err(ZmqError::Other(
                "Unable to send reply. No request in progress",
            )),
        }
    }
}

#[async_trait]
impl BlockingRecv for RepSocket {
    async fn recv(&mut self) -> ZmqResult<ZmqMessage> {
        let mut messages = FuturesUnordered::new();
        loop {
            for peer in self.backend.peers.iter() {
                let peer_id = peer.identity.clone();
                let recv_queue = peer.recv_queue.clone();
                messages.push(async move { (peer_id, recv_queue.lock().await.next().await) });
            }

            if messages.is_empty() {
                // TODO this is super stupid way of waiting for new connections
                // Needs to be refactored
                tokio::time::delay_for(Duration::from_millis(100)).await;
                continue;
            } else {
                break;
            }
        }
        loop {
            match messages.next().await {
                Some((peer_id, Some(Message::MultipartMessage(mut messages)))) => {
                    assert!(messages.len() == 2);
                    assert!(messages[0].data.is_empty()); // Ensure that we have delimeter as first part
                    self.current_request = Some(peer_id);
                    return Ok(messages.pop().unwrap());
                }
                Some((peer_id, None)) => {
                    println!("Peer disconnected {:?}", peer_id);
                    self.backend.peers.remove(&peer_id);
                }
                Some((_peer_id, _)) => todo!(),
                None => continue,
            };
        }
    }
}
<|endoftext|>


<commit_before>/// A rectangle defined by its top-left corner and dimensions
#[derive(Copy, Clone, Debug)]
pub struct Rectangle {
    /// horizontal position of the top-leftcorner of the rectangle, in surface coordinates
    pub x: i32,
    /// vertical position of the top-leftcorner of the rectangle, in surface coordinates
    pub y: i32,
    /// width of the rectangle
    pub width: i32,
    /// height of the rectangle
    pub height: i32,
}

impl Rectangle {
    /// Checks wether given point is inside a rectangle
    pub fn contains(&self, point: (i32, i32)) -> bool {
        let (x, y) = point;
        (x >= self.x) && (x < self.x + self.width)
        && (y >= self.y) && (y < self.y + self.height)
    }
}<commit_msg>utils: fmt<commit_after>/// A rectangle defined by its top-left corner and dimensions
#[derive(Copy, Clone, Debug)]
pub struct Rectangle {
    /// horizontal position of the top-leftcorner of the rectangle, in surface coordinates
    pub x: i32,
    /// vertical position of the top-leftcorner of the rectangle, in surface coordinates
    pub y: i32,
    /// width of the rectangle
    pub width: i32,
    /// height of the rectangle
    pub height: i32,
}

impl Rectangle {
    /// Checks wether given point is inside a rectangle
    pub fn contains(&self, point: (i32, i32)) -> bool {
        let (x, y) = point;
        (x >= self.x) && (x < self.x + self.width) && (y >= self.y) && (y < self.y + self.height)
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq)]
pub enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof,
    // The book doesn't have tokens for comments and
    // whitespaces. Introducing them the scanner can
    // deal with them uniformly and in a more
    // functional way.
    Comment,
    Whitespace,
}

#[derive(Debug)]
pub struct TokenWithContext {
    token: Token,
    lexeme: String, // TODO: make a reference
    line: usize,
}

struct Scanner {
    start: usize,
    current: usize,
    line: usize,
    source: String, // TODO: make a reference
}

fn is_digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

fn is_alpha(c: char) -> bool {
    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
}

fn is_alphanumeric(c: char) -> bool {
    is_digit(c) || is_alpha(c)
}

fn is_whitespace(c: char) -> bool {
    match c {
        ' ' => true,
        '\r' => true,
        '\t' => true,
        '\n' => true,
        _ => false,
    }
}

impl Scanner {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            start: 0,
            current: 0,
            line: 1, // 1-indexed,
            source: source.clone(),
        }
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn char_at(&self, index: usize) -> char {
        // TODO: there must be a better way
        self.source.chars().nth(index).unwrap()
    }

    fn substring(&self, start: usize, end: usize) -> String {
        self.source.chars().skip(start).take(end - start).collect()
    }

    fn peek(&self) -> char() {
        if self.is_at_end() {
            '\0'
        } else {
            self.char_at(self.current)
        }
    }

    fn peek_next(&self) -> char() {
        if self.current + 1 >= self.source.len() {
            '\0'
        } else {
            self.char_at(self.current + 1)
        }
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        let c = self.char_at(self.current - 1);
        if c == '\n' {
            self.line += 1;
        }
        c
    }

    fn is_match(&mut self, expected: char) -> bool {
        if self.is_at_end() {
            return false;
        }
        if self.char_at(self.current) != expected {
            return false;
        }
        self.current += 1;
        return true;
    }

    fn add_context(&self, token: Token) -> TokenWithContext {
        TokenWithContext {
            token: token,
            lexeme: self.substring(self.start, self.current),
            line: self.line,
        }
    }

    fn string(&mut self) -> Result<Token, String> {
        let initial_line = self.line;
        while self.peek() != '"' && !self.is_at_end() {
            self.advance();
        }
        if self.is_at_end() {
            return Err(format!("Unterminated string at line {}", initial_line));
        }
        self.advance();
        Ok(Token::StringLiteral(self.substring(self.start + 1, self.current - 1)))
    }

    fn number(&mut self) -> Token {
        while is_digit(self.peek()) {
            self.advance();
        }
        if self.peek() == '.' && is_digit(self.peek_next()) {
            self.advance(); // Consume the .
            while is_digit(self.peek()) {
                self.advance();
            }
        }
        let literal = self.substring(self.start, self.current);
        let value = literal.parse::<f64>().unwrap();
        Token::NumberLiteral(value)
    }

    fn identifier(&mut self) -> Token {
        while is_alphanumeric(self.peek()) {
            self.advance();
        }
        // TODO: take a ref in the first place
        match self.substring(self.start, self.current).as_ref() {
            "and" => Token::And,
            "class" => Token::Class,
            "else" => Token::Else,
            "false" => Token::False,
            "for" => Token::For,
            "fun" => Token::Fun,
            "if" => Token::If,
            "nil" => Token::Nil,
            "or" => Token::Or,
            "print" => Token::Print,
            "return" => Token::Return,
            "super" => Token::Super,
            "this" => Token::This,
            "true" => Token::True,
            "var" => Token::Var,
            "while" => Token::While,
            identifier => Token::Identifier(identifier.into()),
        }

    }

    fn scan_next(&mut self) -> Result<TokenWithContext, String> {
        self.start = self.current;
        let token = match self.advance() {
            '(' => Token::LeftParen,
            ')' => Token::RightParen,
            '{' => Token::LeftBrace,
            '}' => Token::RightBrace,
            ',' => Token::Comma,
            '.' => Token::Dot,
            '-' => Token::Minus,
            '+' => Token::Plus,
            ';' => Token::Semicolon,
            '*' => Token::Star,
            '!' => {
                if self.is_match('=') {
                    Token::BangEqual
                } else {
                    Token::Bang
                }
            }
            '=' => {
                if self.is_match('=') {
                    Token::EqualEqual
                } else {
                    Token::Equal
                }
            }
            '<' => {
                if self.is_match('=') {
                    Token::LessEqual
                } else {
                    Token::Less
                }
            }
            '>' => {
                if self.is_match('=') {
                    Token::GreaterEqual
                } else {
                    Token::Greater
                }
            }
            '/' => {
                if self.is_match('/') {
                    // Comments go on till the end of the line
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.advance();
                    }
                    Token::Comment
                } else {
                    Token::Slash
                }
            }
            '"' => try!(self.string()),
            c if is_whitespace(c) => Token::Whitespace,
            c if is_digit(c) => self.number(),
            c if is_alpha(c) => self.identifier(),
            c => {
                return Err(format!("Unexpected character {} at line {}, pos {}",
                                   c,
                                   self.line,
                                   self.current - 1));
            }
        };
        Ok(self.add_context(token))
    }
}

pub fn scan(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        let token_with_context = try!(scanner.scan_next());
        match token_with_context.token {
            // Ignoring tokens we don't care about
            Token::Comment => {}
            Token::Whitespace => {}
            _ => tokens.push(token_with_context),
        }
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: "".into(),
        line: scanner.line,
    });
    Ok(tokens)
}

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

    #[test]
    fn single_token() {
        let tokens = scan(&"+".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Plus);
    }

    #[test]
    fn expression() {
        let tokens = scan(&"1+2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn expression_with_whitespaces() {
        let tokens = scan(&"1 + 2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn assignement_with_comment() {
        let tokens = scan(&"var a = 1.0; // A comment".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Eof);
    }

    #[test]
    fn multiline_statements() {
        let tokens = scan(&r#"var a = 1.0;
                              var b = "Hello";"#
                .into())
            .unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Var);
        assert_eq!(tokens[6].token, Token::Identifier("b".into()));
        assert_eq!(tokens[7].token, Token::Equal);
        assert_eq!(tokens[8].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[9].token, Token::Semicolon);
        assert_eq!(tokens[10].token, Token::Eof);
        assert_eq!(tokens[1].line, 1);
        assert_eq!(tokens[9].line, 2);
    }
}
<commit_msg>Scanner doesn't clone the string<commit_after>#[derive(Debug, PartialEq)]
pub enum Token {
    LeftParen,
    RightParen,
    LeftBrace,
    RightBrace,
    Comma,
    Dot,
    Minus,
    Plus,
    Semicolon,
    Slash,
    Star,
    Bang,
    BangEqual,
    Equal,
    EqualEqual,
    Greater,
    GreaterEqual,
    Less,
    LessEqual,
    Identifier(String),
    StringLiteral(String),
    NumberLiteral(f64),
    // Keywords
    And,
    Class,
    Else,
    False,
    Fun,
    For,
    If,
    Nil,
    Or,
    Print,
    Return,
    Super,
    This,
    True,
    Var,
    While,

    Eof,
    // The book doesn't have tokens for comments and
    // whitespaces. Introducing them the scanner can
    // deal with them uniformly and in a more
    // functional way.
    Comment,
    Whitespace,
}

#[derive(Debug)]
pub struct TokenWithContext {
    token: Token,
    // Takes a copy. Tokens can outlive the file they came from
    lexeme: String,
    line: usize,
}

struct Scanner<'a> {
    start: usize,
    current: usize,
    line: usize,
    source: &'a String,
}

fn is_digit(c: char) -> bool {
    c >= '0' && c <= '9'
}

fn is_alpha(c: char) -> bool {
    (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
}

fn is_alphanumeric(c: char) -> bool {
    is_digit(c) || is_alpha(c)
}

fn is_whitespace(c: char) -> bool {
    match c {
        ' ' => true,
        '\r' => true,
        '\t' => true,
        '\n' => true,
        _ => false,
    }
}

impl<'a> Scanner<'a> {
    fn initialize(source: &String) -> Scanner {
        Scanner {
            start: 0,
            current: 0,
            line: 1, // 1-indexed,
            source: source,
        }
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn char_at(&self, index: usize) -> char {
        // TODO: there must be a better way
        self.source.chars().nth(index).unwrap()
    }

    fn substring(&self, start: usize, end: usize) -> String {
        self.source.chars().skip(start).take(end - start).collect()
    }

    fn peek(&self) -> char() {
        if self.is_at_end() {
            '\0'
        } else {
            self.char_at(self.current)
        }
    }

    fn peek_next(&self) -> char() {
        if self.current + 1 >= self.source.len() {
            '\0'
        } else {
            self.char_at(self.current + 1)
        }
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        let c = self.char_at(self.current - 1);
        if c == '\n' {
            self.line += 1;
        }
        c
    }

    fn is_match(&mut self, expected: char) -> bool {
        if self.is_at_end() {
            return false;
        }
        if self.char_at(self.current) != expected {
            return false;
        }
        self.current += 1;
        return true;
    }

    fn add_context(&self, token: Token) -> TokenWithContext {
        TokenWithContext {
            token: token,
            lexeme: self.substring(self.start, self.current),
            line: self.line,
        }
    }

    fn string(&mut self) -> Result<Token, String> {
        let initial_line = self.line;
        while self.peek() != '"' && !self.is_at_end() {
            self.advance();
        }
        if self.is_at_end() {
            return Err(format!("Unterminated string at line {}", initial_line));
        }
        self.advance();
        Ok(Token::StringLiteral(self.substring(self.start + 1, self.current - 1)))
    }

    fn number(&mut self) -> Token {
        while is_digit(self.peek()) {
            self.advance();
        }
        if self.peek() == '.' && is_digit(self.peek_next()) {
            self.advance(); // Consume the .
            while is_digit(self.peek()) {
                self.advance();
            }
        }
        let literal = self.substring(self.start, self.current);
        let value = literal.parse::<f64>().unwrap();
        Token::NumberLiteral(value)
    }

    fn identifier(&mut self) -> Token {
        while is_alphanumeric(self.peek()) {
            self.advance();
        }
        // TODO: take a ref in the first place
        match self.substring(self.start, self.current).as_ref() {
            "and" => Token::And,
            "class" => Token::Class,
            "else" => Token::Else,
            "false" => Token::False,
            "for" => Token::For,
            "fun" => Token::Fun,
            "if" => Token::If,
            "nil" => Token::Nil,
            "or" => Token::Or,
            "print" => Token::Print,
            "return" => Token::Return,
            "super" => Token::Super,
            "this" => Token::This,
            "true" => Token::True,
            "var" => Token::Var,
            "while" => Token::While,
            identifier => Token::Identifier(identifier.into()),
        }

    }

    fn scan_next(&mut self) -> Result<TokenWithContext, String> {
        self.start = self.current;
        let token = match self.advance() {
            '(' => Token::LeftParen,
            ')' => Token::RightParen,
            '{' => Token::LeftBrace,
            '}' => Token::RightBrace,
            ',' => Token::Comma,
            '.' => Token::Dot,
            '-' => Token::Minus,
            '+' => Token::Plus,
            ';' => Token::Semicolon,
            '*' => Token::Star,
            '!' => {
                if self.is_match('=') {
                    Token::BangEqual
                } else {
                    Token::Bang
                }
            }
            '=' => {
                if self.is_match('=') {
                    Token::EqualEqual
                } else {
                    Token::Equal
                }
            }
            '<' => {
                if self.is_match('=') {
                    Token::LessEqual
                } else {
                    Token::Less
                }
            }
            '>' => {
                if self.is_match('=') {
                    Token::GreaterEqual
                } else {
                    Token::Greater
                }
            }
            '/' => {
                if self.is_match('/') {
                    // Comments go on till the end of the line
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.advance();
                    }
                    Token::Comment
                } else {
                    Token::Slash
                }
            }
            '"' => try!(self.string()),
            c if is_whitespace(c) => Token::Whitespace,
            c if is_digit(c) => self.number(),
            c if is_alpha(c) => self.identifier(),
            c => {
                return Err(format!("Unexpected character {} at line {}, pos {}",
                                   c,
                                   self.line,
                                   self.current - 1));
            }
        };
        Ok(self.add_context(token))
    }
}

pub fn scan(source: &String) -> Result<Vec<TokenWithContext>, String> {
    let mut scanner = Scanner::initialize(source);
    let mut tokens = Vec::new();
    while !scanner.is_at_end() {
        let token_with_context = try!(scanner.scan_next());
        match token_with_context.token {
            // Ignoring tokens we don't care about
            Token::Comment => {}
            Token::Whitespace => {}
            _ => tokens.push(token_with_context),
        }
    }
    tokens.push(TokenWithContext {
        token: Token::Eof,
        lexeme: "".into(),
        line: scanner.line,
    });
    Ok(tokens)
}

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

    #[test]
    fn single_token() {
        let tokens = scan(&"+".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Plus);
    }

    #[test]
    fn expression() {
        let tokens = scan(&"1+2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn expression_with_whitespaces() {
        let tokens = scan(&"1 + 2".into()).unwrap();
        assert_eq!(tokens[0].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[1].token, Token::Plus);
        assert_eq!(tokens[2].token, Token::NumberLiteral(2.0f64));
        assert_eq!(tokens[3].token, Token::Eof);
    }

    #[test]
    fn assignement_with_comment() {
        let tokens = scan(&"var a = 1.0; // A comment".into()).unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Eof);
    }

    #[test]
    fn multiline_statements() {
        let tokens = scan(&r#"var a = 1.0;
                              var b = "Hello";"#
                .into())
            .unwrap();
        assert_eq!(tokens[0].token, Token::Var);
        assert_eq!(tokens[1].token, Token::Identifier("a".into()));
        assert_eq!(tokens[2].token, Token::Equal);
        assert_eq!(tokens[3].token, Token::NumberLiteral(1.0f64));
        assert_eq!(tokens[4].token, Token::Semicolon);
        assert_eq!(tokens[5].token, Token::Var);
        assert_eq!(tokens[6].token, Token::Identifier("b".into()));
        assert_eq!(tokens[7].token, Token::Equal);
        assert_eq!(tokens[8].token, Token::StringLiteral("Hello".into()));
        assert_eq!(tokens[9].token, Token::Semicolon);
        assert_eq!(tokens[10].token, Token::Eof);
        assert_eq!(tokens[1].line, 1);
        assert_eq!(tokens[9].line, 2);
    }
}
<|endoftext|>


<commit_before>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * 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/
 */
//! Primitives for energy computation.
//!
//! This module provides simple function to compute separated components of the
//! potential energy of an `Universe`.
use universe::Universe;

/// An helper struct to evaluate energy components of an universe.
pub struct EnergyEvaluator<'a> {
    universe: &'a Universe,
}

impl<'a> EnergyEvaluator<'a> {
    /// Create a new energy evaluator acting on the given `universe`.
    pub fn new(universe: &'a Universe) -> EnergyEvaluator<'a> {
        EnergyEvaluator {
            universe: universe,
        }
    }
}

impl<'a> EnergyEvaluator<'a> {
    /// Compute the energy associated with the pair of particles `i, j`
    #[inline]
    pub fn pair(&self, i: usize, j: usize) -> f64 {
        let mut energy = 0.0;
        let r = self.universe.wraped_vector(i, j).norm();
        for &(ref potential, ref restriction) in self.universe.pair_potentials(i, j) {
            if !restriction.is_excluded_pair(self.universe, i, j) {
                let s = restriction.scaling(self.universe, i, j);
                energy += s * potential.energy(r);
            }
        }
        return energy;
    }

    /// Compute the energy of all the pairs in the system
    pub fn pairs(&self) -> f64 {
        let mut energy = 0.0;
        for i in 0..self.universe.size() {
            for j in (i+1)..self.universe.size() {
                energy += self.pair(i, j);
            }
        }
        return energy;
    }

    /// Compute the energy associated with the bonded particles `i, j`
    #[inline]
    pub fn bond(&self, i: usize, j: usize) -> f64 {
        let mut energy = 0.0;
        let r = self.universe.wraped_vector(i, j).norm();
        for potential in self.universe.bond_potentials(i, j) {
            energy += potential.energy(r);
        }
        return energy;
    }

    /// Compute the energy of all the bonds in the system
    pub fn bonds(&self) -> f64 {
        let mut energy = 0.0;
        for molecule in self.universe.molecules() {
            for bond in molecule.bonds() {
                let (i, j) = (bond.i(), bond.j());
                energy += self.bond(i, j);
            }
        }
        return energy;
    }

    /// Compute the energy associated with the angle `i, j, k`
    #[inline]
    pub fn angle(&self, i: usize, j: usize, k: usize) -> f64 {
        let mut energy = 0.0;
        let theta = self.universe.angle(i, j, k);
        for potential in self.universe.angle_potentials(i, j, k) {
            energy += potential.energy(theta);
        }
        return energy;
    }

    /// Compute the energy of all the angles in the system
    pub fn angles(&self) -> f64 {
        let mut energy = 0.0;
        for molecule in self.universe.molecules() {
            for angle in molecule.angles() {
                let (i, j, k) = (angle.i(), angle.j(), angle.k());
                energy += self.angle(i, j, k);
            }
        }
        return energy;
    }

    /// Compute the energy associated with the dihedral angle `i, j, k, m`
    #[inline]
    pub fn dihedral(&self, i: usize, j: usize, k: usize, m: usize) -> f64 {
        let mut energy = 0.0;
        let phi = self.universe.dihedral(i, j, k, m);
        for potential in self.universe.dihedral_potentials(i, j, k, m) {
            energy += potential.energy(phi);
        }
        return energy;
    }

    /// Compute the energy of all the dihedral angles in the system
    pub fn dihedrals(&self) -> f64 {
        let mut energy = 0.0;
        for molecule in self.universe.molecules() {
            for dihedral in molecule.dihedrals() {
                let (i, j, k, m) = (dihedral.i(), dihedral.j(), dihedral.k(), dihedral.m());
                energy += self.dihedral(i, j, k, m);
            }
        }
        return energy;
    }

    /// Compute the energy of the molecule interaction, *i.e.* the sum `bonds +
    /// angles + dihedrals`.
    #[inline]
    pub fn molecules(&self) -> f64 {
        return self.bonds() + self.angles() + self.dihedrals();
    }

    /// Compute the energy of the electrostatic interactions
    #[inline]
    pub fn coulomb(&self) -> f64 {
        if let Some(ref coulomb) = *self.universe.coulomb_potential() {
            coulomb.energy(self.universe)
        } else {
            0.0
        }
    }

    /// Compute the energy of the global potentials
    #[inline]
    pub fn global(&self) -> f64 {
        let mut energy = 0.0;
        for global in self.universe.global_potentials() {
            energy += global.energy(self.universe);
        }
        return energy;
    }
}

#[cfg(test)]
mod tests {
    // This code is tested in the src/simulation/compute.rs file, as it is used
    // by the PotentialEnergy compute.
}
<commit_msg>Energy evaluator function take a distance (angle) parameter<commit_after>/* Cymbalum, Molecular Simulation in Rust - Copyright (C) 2015 Guillaume Fraux
 *
 * 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/
 */
//! Primitives for energy computation.
//!
//! This module provides simple function to compute separated components of the
//! potential energy of an `Universe`.
use universe::Universe;

/// An helper struct to evaluate energy components of an universe.
pub struct EnergyEvaluator<'a> {
    universe: &'a Universe,
}

impl<'a> EnergyEvaluator<'a> {
    /// Create a new energy evaluator acting on the given `universe`.
    pub fn new(universe: &'a Universe) -> EnergyEvaluator<'a> {
        EnergyEvaluator {
            universe: universe,
        }
    }
}

impl<'a> EnergyEvaluator<'a> {
    /// Compute the energy associated with the pair of particles `i, j` at
    /// distance `r`
    #[inline]
    pub fn pair(&self, r: f64, i: usize, j: usize) -> f64 {
        let mut energy = 0.0;
        for &(ref potential, ref restriction) in self.universe.pair_potentials(i, j) {
            if !restriction.is_excluded_pair(self.universe, i, j) {
                let s = restriction.scaling(self.universe, i, j);
                energy += s * potential.energy(r);
            }
        }
        return energy;
    }

    /// Compute the energy of all the pairs in the system
    pub fn pairs(&self) -> f64 {
        let mut energy = 0.0;
        for i in 0..self.universe.size() {
            for j in (i+1)..self.universe.size() {
                let r = self.universe.wraped_vector(i, j).norm();
                energy += self.pair(r, i, j);
            }
        }
        return energy;
    }

    /// Compute the energy associated with the bonded particles `i, j` at
    /// distance `r`
    #[inline]
    pub fn bond(&self, r: f64, i: usize, j: usize) -> f64 {
        let mut energy = 0.0;
        for potential in self.universe.bond_potentials(i, j) {
            energy += potential.energy(r);
        }
        return energy;
    }

    /// Compute the energy of all the bonds in the system
    pub fn bonds(&self) -> f64 {
        let mut energy = 0.0;
        for molecule in self.universe.molecules() {
            for bond in molecule.bonds() {
                let (i, j) = (bond.i(), bond.j());
                let r = self.universe.wraped_vector(i, j).norm();
                energy += self.bond(r, i, j);
            }
        }
        return energy;
    }

    /// Compute the energy associated with the angle `i, j, k` at angle `theta`
    #[inline]
    pub fn angle(&self, theta: f64, i: usize, j: usize, k: usize) -> f64 {
        let mut energy = 0.0;
        for potential in self.universe.angle_potentials(i, j, k) {
            energy += potential.energy(theta);
        }
        return energy;
    }

    /// Compute the energy of all the angles in the system
    pub fn angles(&self) -> f64 {
        let mut energy = 0.0;
        for molecule in self.universe.molecules() {
            for angle in molecule.angles() {
                let (i, j, k) = (angle.i(), angle.j(), angle.k());
                let theta = self.universe.angle(i, j, k);
                energy += self.angle(theta, i, j, k);
            }
        }
        return energy;
    }

    /// Compute the energy associated with the dihedral angle `i, j, k, m` at
    /// angle `phi`
    #[inline]
    pub fn dihedral(&self, phi: f64, i: usize, j: usize, k: usize, m: usize) -> f64 {
        let mut energy = 0.0;
        for potential in self.universe.dihedral_potentials(i, j, k, m) {
            energy += potential.energy(phi);
        }
        return energy;
    }

    /// Compute the energy of all the dihedral angles in the system
    pub fn dihedrals(&self) -> f64 {
        let mut energy = 0.0;
        for molecule in self.universe.molecules() {
            for dihedral in molecule.dihedrals() {
                let (i, j, k, m) = (dihedral.i(), dihedral.j(), dihedral.k(), dihedral.m());
                let phi = self.universe.dihedral(i, j, k, m);
                energy += self.dihedral(phi, i, j, k, m);
            }
        }
        return energy;
    }

    /// Compute the energy of the molecule interaction, *i.e.* the sum `bonds +
    /// angles + dihedrals`.
    #[inline]
    pub fn molecules(&self) -> f64 {
        return self.bonds() + self.angles() + self.dihedrals();
    }

    /// Compute the energy of the electrostatic interactions
    #[inline]
    pub fn coulomb(&self) -> f64 {
        if let Some(ref coulomb) = *self.universe.coulomb_potential() {
            coulomb.energy(self.universe)
        } else {
            0.0
        }
    }

    /// Compute the energy of the global potentials
    #[inline]
    pub fn global(&self) -> f64 {
        let mut energy = 0.0;
        for global in self.universe.global_potentials() {
            energy += global.energy(self.universe);
        }
        return energy;
    }
}

#[cfg(test)]
mod tests {
    // This code is tested in the src/simulation/compute.rs file, as it is used
    // by the PotentialEnergy compute.
}
<|endoftext|>


<commit_before>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

//! DHT service

use std::sync;

use super::GenericNodeTable;
use super::GenericRpc;

// TODO(divius): implement
/// Structure representing main DHT service.
#[experimental]
pub struct Service<TNodeTable:GenericNodeTable, TRpc:GenericRpc> {
    node_table: sync::Arc<sync::RWLock<TNodeTable>>,
    rpc: sync::Arc<TRpc>,
}

#[experimental]
impl<TNodeTable:GenericNodeTable, TRpc:GenericRpc> Service<TNodeTable, TRpc> {
    /// Create new service with given node table and RPC implementations.
    pub fn new(node_table: TNodeTable, rpc: TRpc) -> Service<TNodeTable, TRpc> {
        Service {
            node_table: sync::Arc::new(sync::RWLock::new(node_table)),
            rpc: sync::Arc::new(rpc),
        }
    }

    /// Get lock object for a node_table.
    pub fn node_table(&self) -> &sync::RWLock<TNodeTable> {
        self.node_table.deref()
    }

    /// Get instanc of RPC object.
    pub fn rpc(&self) -> &TRpc {
        self.rpc.deref()
    }
}

#[cfg(test)]
mod test {
    use std::sync;

    use num;

    use super::super::base::{mod, GenericNodeTable, GenericRpc};

    use super::Service;

    use super::super::utils::test;

    struct DummyNodeTable {
        last_node: Option<base::Node>,
    }

    impl GenericNodeTable for DummyNodeTable {
        fn random_id(&self) -> num::BigUint {
            // This number is random, I promise :)
            test::uint_to_id(42)
        }

        fn update(&mut self, node: &base::Node) -> bool {
            self.last_node = Some(node.clone());
            true
        }
        #[allow(unused_variable)]
        fn find(&self, id: &num::BigUint, count: uint) -> Vec<base::Node> {
            match self.last_node {
                Some(ref n) if n.id == *id => vec![n.clone()],
                _ => vec![]
            }
        }
        fn pop_oldest(&mut self) -> Vec<base::Node> {
            vec![]
        }
    }

    struct DummyRpc;
    impl GenericRpc for DummyRpc {
        #[allow(unused_variable)]
        fn ping(&self, node: &base::Node) -> sync::Future<bool> {
            sync::Future::from_value(true)
        }
        #[allow(unused_variable)]
        fn find_node(&self, id: &num::BigUint) -> sync::Future<base::LookupResult> {
            sync::Future::from_value(base::NodeFound(test::new_node(100500)))
        }
    }

    #[test]
    fn test_new() {
        let s = Service::new(DummyNodeTable { last_node: None }, DummyRpc);
        let g = s.node_table().write();
        assert_eq!(0, g.find(&test::uint_to_id(42), 1).len());
        assert!(s.rpc().ping(&test::new_node(42)).get());
    }
}
<commit_msg>Service: new(rpc), old new -> with_node_table<commit_after>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

//! DHT service

use std::sync;

use super::base::{mod, GenericNodeTable, GenericRpc};
use super::knodetable;

// TODO(divius): implement
/// Structure representing main DHT service.
#[experimental]
pub struct Service<TNodeTable:GenericNodeTable, TRpc:GenericRpc> {
    node_table: sync::Arc<sync::RWLock<TNodeTable>>,
    rpc: sync::Arc<TRpc>,
}

#[experimental]
impl<TRpc:GenericRpc> Service<knodetable::KNodeTable, TRpc> {
    /// Create new service with given RPC implementation.
    pub fn new(this_node: &base::Node, rpc: TRpc) -> Service<knodetable::KNodeTable, TRpc> {
        Service::with_node_table(
            knodetable::KNodeTable::new(this_node.id.clone()), rpc)
    }
}

#[experimental]
impl<TNodeTable:GenericNodeTable, TRpc:GenericRpc> Service<TNodeTable, TRpc> {
    /// Create new service with given node table and RPC implementations.
    pub fn with_node_table(node_table: TNodeTable, rpc: TRpc)
            -> Service<TNodeTable, TRpc> {
        Service {
            node_table: sync::Arc::new(sync::RWLock::new(node_table)),
            rpc: sync::Arc::new(rpc),
        }
    }

    /// Get lock object for a node_table.
    pub fn node_table(&self) -> &sync::RWLock<TNodeTable> {
        self.node_table.deref()
    }

    /// Get instanc of RPC object.
    pub fn rpc(&self) -> &TRpc {
        self.rpc.deref()
    }
}

#[cfg(test)]
mod test {
    use std::sync;

    use num;

    use super::super::base::{mod, GenericNodeTable, GenericRpc};

    use super::Service;

    use super::super::utils::test;

    struct DummyNodeTable {
        last_node: Option<base::Node>,
    }

    impl GenericNodeTable for DummyNodeTable {
        fn random_id(&self) -> num::BigUint {
            // This number is random, I promise :)
            test::uint_to_id(42)
        }

        fn update(&mut self, node: &base::Node) -> bool {
            self.last_node = Some(node.clone());
            true
        }
        #[allow(unused_variable)]
        fn find(&self, id: &num::BigUint, count: uint) -> Vec<base::Node> {
            match self.last_node {
                Some(ref n) if n.id == *id => vec![n.clone()],
                _ => vec![]
            }
        }
        fn pop_oldest(&mut self) -> Vec<base::Node> {
            vec![]
        }
    }

    struct DummyRpc;
    impl GenericRpc for DummyRpc {
        #[allow(unused_variable)]
        fn ping(&self, node: &base::Node) -> sync::Future<bool> {
            sync::Future::from_value(true)
        }
        #[allow(unused_variable)]
        fn find_node(&self, id: &num::BigUint) -> sync::Future<base::LookupResult> {
            sync::Future::from_value(base::NodeFound(test::new_node(100500)))
        }
    }

    #[test]
    fn test_new() {
        let s = Service::new(&test::new_node(1), DummyRpc);
        let g = s.node_table().write();
        assert_eq!(0, g.find(&test::uint_to_id(42), 1).len());
        assert!(s.rpc().ping(&test::new_node(42)).get());
    }

    #[test]
    fn test_with_node_table() {
        let s = Service::with_node_table(DummyNodeTable { last_node: None },
                                         DummyRpc);
        let g = s.node_table().write();
        assert_eq!(0, g.find(&test::uint_to_id(42), 1).len());
        assert!(s.rpc().ping(&test::new_node(42)).get());
    }
}
<|endoftext|>


<commit_before>/// Utilities to make it easier to maintain Janus session state between plugin callbacks.

use std::ops::Deref;
use std::sync::Arc;
use super::PluginHandle;

/// A representation of session state associated with a Janus plugin session handle.
#[derive(Debug)]
pub struct SessionHandle<T> {
    pub handle: *mut PluginHandle,
    state: T,
}

impl<T> SessionHandle<T> {

    /// Allocates a boxed, reference-counted SessionHandle associated with an opaque Janus handle
    /// (whose plugin_handle will then point to the contents of the box).
    pub fn establish(handle: *mut PluginHandle, state: T) -> Box<Arc<Self>> {
        let result = Box::new(Arc::new(Self { handle, state: state }));
        unsafe { (*handle).plugin_handle = result.as_ref() as *const _ as *mut _ };
        result
    }

    /// Retrieves the reference-counted SessionHandle pointed to by an opaque Janus handle.
    pub fn from_ptr<'a>(handle: *mut PluginHandle) -> &'a Arc<Self> {
        unsafe { &*((*handle).plugin_handle as *mut Arc<Self>) }
    }
}

impl<T> Deref for SessionHandle<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.state
    }
}

// the pointer is opaque to Janus code, so this handle is threadsafe to the extent that the state is

unsafe impl<T: Sync> Sync for SessionHandle<T> {}
unsafe impl<T: Send> Send for SessionHandle<T> {}
<commit_msg>Add test for session handle<commit_after>/// Utilities to make it easier to maintain Janus session state between plugin callbacks.

use std::ops::Deref;
use std::sync::Arc;
use super::PluginHandle;

/// A representation of session state associated with a Janus plugin session handle.
#[derive(Debug)]
pub struct SessionHandle<T> {
    pub handle: *mut PluginHandle,
    state: T,
}

impl<T> SessionHandle<T> {

    /// Allocates a boxed, reference-counted SessionHandle associated with an opaque Janus handle
    /// (whose plugin_handle will then point to the contents of the box).
    pub fn establish(handle: *mut PluginHandle, state: T) -> Box<Arc<Self>> {
        let result = Box::new(Arc::new(Self { handle, state: state }));
        unsafe { (*handle).plugin_handle = result.as_ref() as *const _ as *mut _ };
        result
    }

    /// Retrieves the reference-counted SessionHandle pointed to by an opaque Janus handle.
    pub fn from_ptr<'a>(handle: *mut PluginHandle) -> &'a Arc<Self> {
        unsafe { &*((*handle).plugin_handle as *mut Arc<Self>) }
    }
}

impl<T> Deref for SessionHandle<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.state
    }
}

// the pointer is opaque to Janus code, so this handle is threadsafe to the extent that the state is

unsafe impl<T: Sync> Sync for SessionHandle<T> {}
unsafe impl<T: Send> Send for SessionHandle<T> {}

#[cfg(test)]
mod tests {

    use super::*;
    use std::ptr;

    #[test]
    fn session_handle_roundtrip() {
        struct State(i32);
        let mut handle = PluginHandle {
            gateway_handle: ptr::null_mut(),
            plugin_handle: ptr::null_mut(),
            stopped_bitfield: 0,
            __padding: Default::default()
        };
        let ptr = &mut handle as *mut _;
        let session = SessionHandle::establish(ptr, State(42));
        assert_eq!(session.as_ref() as *const _ as *mut _, handle.plugin_handle);
        assert_eq!(SessionHandle::<State>::from_ptr(ptr).state.0, 42);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::str::{from_utf8, Utf8Error};

use netbuf::Buf;
use futures::{Future, Async, Poll};
use futures::Async::{Ready, NotReady};
use futures::stream::{Stream};
use tokio_core::io::Io;
use tokio_core::channel::Receiver;
use tokio_core::reactor::Handle;
use tk_bufstream::IoBuf;
use byteorder::{BigEndian, ByteOrder};

use super::{Dispatcher, ImmediateReplier, RemoteReplier, OutFrame};
use self::Frame::*;

const MAX_MESSAGE_SIZE: u64 = 128 << 10;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: io::Error) {
            description("IO error")
            display("IO error: {}", err)
            from()
        }
        InvalidUtf8(err: Utf8Error) {
            description("Error decoding text frame")
            display("Error decoding text frame: {}", err)
            from()
        }
        InvalidOpcode(code: u8) {
            description("Opcode of the frame is invalid")
            display("Opcode of the frame is invalid: {}", code)
            from()
        }
        Unmasked {
            description("Received unmasked frame")
        }
        TooLong {
            description("Received frame that is too long")
        }
    }
}

pub struct WebsockProto<S: Io, D: Dispatcher> {
    dispatcher: D,
    io: IoBuf<S>,
    remote: RemoteReplier,
    recv: Receiver<OutFrame>,
}

pub enum Frame<'a> {
    Ping(&'a [u8]),
    Pong(&'a [u8]),
    Text(&'a str),
    Binary(&'a [u8]),
}

fn parse_frame<'x>(buf: &'x mut Buf) -> Poll<(Frame<'x>, usize), Error> {
    if buf.len() < 2 {
        return Ok(NotReady);
    }
    let (size, fsize) = {
        match buf[1] & 0x7F {
            126 => {
                if buf.len() < 4 {
                    return Ok(NotReady);
                }
                (BigEndian::read_u16(&buf[2..4]) as u64, 4)
            }
            127 => {
                if buf.len() < 10 {
                    return Ok(NotReady);
                }
                (BigEndian::read_u64(&buf[2..10]), 10)
            }
            size => (size as u64, 2),
        }
    };
    if size > MAX_MESSAGE_SIZE {
        return Err(Error::TooLong);
    }
    let size = size as usize;
    let start = fsize + 4 /* mask size */;
    if buf.len() < start + size {
        return Ok(NotReady);
    }

    let fin = buf[0] & 0x80 != 0;
    let opcode = buf[0] & 0x0F;
    // TODO(tailhook) should we assert that reserved bits are zero?
    let mask = buf[1] & 0x80 != 0;
    if !fin {
        unimplemented!();  // framed(chunked) messages
    }
    if !mask {
        return Err(Error::Unmasked);
    }
    let mask = [buf[start-4], buf[start-3], buf[start-2], buf[start-1]];
    for idx in 0..size { // hopefully llvm is smart enough to optimize it
        buf[start + idx] ^= mask[idx % 4];
    }
    let data = &buf[start..(start + size)];
    let frame = match opcode {
        0x9 => Ping(data),
        0xA => Pong(data),
        0x1 => Text(try!(from_utf8(data))),
        0x2 => Binary(data),
        // TODO(tailhook) implement shutdown packets
        x => return Err(Error::InvalidOpcode(x)),
    };
    return Ok(Ready((frame, start + size)));
}

impl<D, S: Io> Future for WebsockProto<S, D>
    where D: Dispatcher,
{
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<(), Error> {
        loop {
            try!(self.poll_recv());
            try!(self.io.flush());
            let packet_len = if let Ready((frame, bytes)) =
                try!(parse_frame(&mut self.io.in_buf))
            {
                try!(self.dispatcher.dispatch(frame,
                    &mut ImmediateReplier::new(&mut self.io.out_buf),
                    &self.remote));
                Some(bytes)
            } else {
                None
            };
            if let Some(packet_len) = packet_len {
                self.io.in_buf.consume(packet_len);
            } else {
                let nbytes = try!(self.io.read());
                if nbytes == 0 {
                    if self.io.done() {
                        return Ok(Async::Ready(()));
                    } else {
                        return Ok(Async::NotReady);
                    }
                } else {
                    continue;
                }
            };
        }
    }
}

impl<S: Io, D> WebsockProto<S, D>
    where D: Dispatcher,
{
    pub fn new(sock: IoBuf<S>, dispatcher: D, handle: &Handle)
        -> WebsockProto<S, D>
    {
        let (tx, rx) = RemoteReplier::pair(handle);
        WebsockProto {
            io: sock,
            dispatcher: dispatcher,
            remote: tx,
            recv: rx,
        }
    }

    fn poll_recv(&mut self) -> Result<(), Error> {
        if let Ready(Some(frame)) = try!(self.recv.poll()) {
            let mut imm = ImmediateReplier::new(&mut self.io.out_buf);
            match frame {
                OutFrame::Text(val) => {
                    imm.text(&val);
                }
                OutFrame::Binary(val) => {
                    imm.binary(&val);
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Clean error on fragmented frames<commit_after>use std::io;
use std::str::{from_utf8, Utf8Error};

use netbuf::Buf;
use futures::{Future, Async, Poll};
use futures::Async::{Ready, NotReady};
use futures::stream::{Stream};
use tokio_core::io::Io;
use tokio_core::channel::Receiver;
use tokio_core::reactor::Handle;
use tk_bufstream::IoBuf;
use byteorder::{BigEndian, ByteOrder};

use super::{Dispatcher, ImmediateReplier, RemoteReplier, OutFrame};
use self::Frame::*;

const MAX_MESSAGE_SIZE: u64 = 128 << 10;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: io::Error) {
            description("IO error")
            display("IO error: {}", err)
            from()
        }
        InvalidUtf8(err: Utf8Error) {
            description("Error decoding text frame")
            display("Error decoding text frame: {}", err)
            from()
        }
        InvalidOpcode(code: u8) {
            description("Opcode of the frame is invalid")
            display("Opcode of the frame is invalid: {}", code)
            from()
        }
        Unmasked {
            description("Received unmasked frame")
        }
        Framented {
            description("Received fragmented frame")
        }
        TooLong {
            description("Received frame that is too long")
        }
    }
}

pub struct WebsockProto<S: Io, D: Dispatcher> {
    dispatcher: D,
    io: IoBuf<S>,
    remote: RemoteReplier,
    recv: Receiver<OutFrame>,
}

pub enum Frame<'a> {
    Ping(&'a [u8]),
    Pong(&'a [u8]),
    Text(&'a str),
    Binary(&'a [u8]),
}

fn parse_frame<'x>(buf: &'x mut Buf) -> Poll<(Frame<'x>, usize), Error> {
    if buf.len() < 2 {
        return Ok(NotReady);
    }
    let (size, fsize) = {
        match buf[1] & 0x7F {
            126 => {
                if buf.len() < 4 {
                    return Ok(NotReady);
                }
                (BigEndian::read_u16(&buf[2..4]) as u64, 4)
            }
            127 => {
                if buf.len() < 10 {
                    return Ok(NotReady);
                }
                (BigEndian::read_u64(&buf[2..10]), 10)
            }
            size => (size as u64, 2),
        }
    };
    if size > MAX_MESSAGE_SIZE {
        return Err(Error::TooLong);
    }
    let size = size as usize;
    let start = fsize + 4 /* mask size */;
    if buf.len() < start + size {
        return Ok(NotReady);
    }

    let fin = buf[0] & 0x80 != 0;
    let opcode = buf[0] & 0x0F;
    // TODO(tailhook) should we assert that reserved bits are zero?
    let mask = buf[1] & 0x80 != 0;
    if !fin {
        return Err(Error::Fragmented);
    }
    if !mask {
        return Err(Error::Unmasked);
    }
    let mask = [buf[start-4], buf[start-3], buf[start-2], buf[start-1]];
    for idx in 0..size { // hopefully llvm is smart enough to optimize it
        buf[start + idx] ^= mask[idx % 4];
    }
    let data = &buf[start..(start + size)];
    let frame = match opcode {
        0x9 => Ping(data),
        0xA => Pong(data),
        0x1 => Text(try!(from_utf8(data))),
        0x2 => Binary(data),
        // TODO(tailhook) implement shutdown packets
        x => return Err(Error::InvalidOpcode(x)),
    };
    return Ok(Ready((frame, start + size)));
}

impl<D, S: Io> Future for WebsockProto<S, D>
    where D: Dispatcher,
{
    type Item = ();
    type Error = Error;
    fn poll(&mut self) -> Poll<(), Error> {
        loop {
            try!(self.poll_recv());
            try!(self.io.flush());
            let packet_len = if let Ready((frame, bytes)) =
                try!(parse_frame(&mut self.io.in_buf))
            {
                try!(self.dispatcher.dispatch(frame,
                    &mut ImmediateReplier::new(&mut self.io.out_buf),
                    &self.remote));
                Some(bytes)
            } else {
                None
            };
            if let Some(packet_len) = packet_len {
                self.io.in_buf.consume(packet_len);
            } else {
                let nbytes = try!(self.io.read());
                if nbytes == 0 {
                    if self.io.done() {
                        return Ok(Async::Ready(()));
                    } else {
                        return Ok(Async::NotReady);
                    }
                } else {
                    continue;
                }
            };
        }
    }
}

impl<S: Io, D> WebsockProto<S, D>
    where D: Dispatcher,
{
    pub fn new(sock: IoBuf<S>, dispatcher: D, handle: &Handle)
        -> WebsockProto<S, D>
    {
        let (tx, rx) = RemoteReplier::pair(handle);
        WebsockProto {
            io: sock,
            dispatcher: dispatcher,
            remote: tx,
            recv: rx,
        }
    }

    fn poll_recv(&mut self) -> Result<(), Error> {
        if let Ready(Some(frame)) = try!(self.recv.poll()) {
            let mut imm = ImmediateReplier::new(&mut self.io.out_buf);
            match frame {
                OutFrame::Text(val) => {
                    imm.text(&val);
                }
                OutFrame::Binary(val) => {
                    imm.binary(&val);
                }
            }
        }
        Ok(())
    }
}
<|endoftext|>


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

//! Span debugger
//!
//! This module shows spans for all expressions in the crate
//! to help with compiler debugging.

use syntax::ast;
use syntax::visit;
use syntax::visit::Visitor;

use driver::session::Session;

struct ShowSpanVisitor<'a> {
    sess: &'a Session
}

impl<'a> Visitor<()> for ShowSpanVisitor<'a> {
    fn visit_expr(&mut self, e: &ast::Expr, _: ()) {
        self.sess.span_note(e.span, "expression");
        visit::walk_expr(self, e, ());
    }
}

pub fn run(sess: &Session, krate: &ast::Crate) {
    let mut v = ShowSpanVisitor { sess: sess };
    visit::walk_crate(&mut v, krate, ());
}
<commit_msg>auto merge of #17142 : sfackler/rust/issue-17115, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Span debugger
//!
//! This module shows spans for all expressions in the crate
//! to help with compiler debugging.

use syntax::ast;
use syntax::visit;
use syntax::visit::Visitor;

use driver::session::Session;

struct ShowSpanVisitor<'a> {
    sess: &'a Session
}

impl<'a> Visitor<()> for ShowSpanVisitor<'a> {
    fn visit_expr(&mut self, e: &ast::Expr, _: ()) {
        self.sess.span_note(e.span, "expression");
        visit::walk_expr(self, e, ());
    }

    fn visit_mac(&mut self, macro: &ast::Mac, e: ()) {
        visit::walk_mac(self, macro, e);
    }
}

pub fn run(sess: &Session, krate: &ast::Crate) {
    let mut v = ShowSpanVisitor { sess: sess };
    visit::walk_crate(&mut v, krate, ());
}
<|endoftext|>


<commit_before>use crate::common::CompositeFile;
use crate::directory::FileSlice;
use crate::fastfield::MultiValuedFastFieldReader;
use crate::fastfield::{BitpackedFastFieldReader, FastFieldNotAvailableError};
use crate::fastfield::{BytesFastFieldReader, FastValue};
use crate::schema::{Cardinality, Field, FieldType, Schema};
use crate::space_usage::PerFieldSpaceUsage;
use crate::TantivyError;

use super::reader::DynamicFastFieldReader;
use super::FastFieldReader;

/// Provides access to all of the BitpackedFastFieldReader.
///
/// Internally, `FastFieldReaders` have preloaded fast field readers,
/// and just wraps several `HashMap`.
#[derive(Clone)]
pub struct FastFieldReaders {
    schema: Schema,
    fast_fields_composite: CompositeFile,
}
#[derive(Eq, PartialEq, Debug)]
enum FastType {
    I64,
    U64,
    F64,
    Date,
}

fn type_and_cardinality(field_type: &FieldType) -> Option<(FastType, Cardinality)> {
    match field_type {
        FieldType::U64(options) => options
            .get_fastfield_cardinality()
            .map(|cardinality| (FastType::U64, cardinality)),
        FieldType::I64(options) => options
            .get_fastfield_cardinality()
            .map(|cardinality| (FastType::I64, cardinality)),
        FieldType::F64(options) => options
            .get_fastfield_cardinality()
            .map(|cardinality| (FastType::F64, cardinality)),
        FieldType::Date(options) => options
            .get_fastfield_cardinality()
            .map(|cardinality| (FastType::Date, cardinality)),
        FieldType::HierarchicalFacet(_) => Some((FastType::U64, Cardinality::MultiValues)),
        _ => None,
    }
}

impl FastFieldReaders {
    pub(crate) fn new(schema: Schema, fast_fields_composite: CompositeFile) -> FastFieldReaders {
        FastFieldReaders {
            schema,
            fast_fields_composite,
        }
    }

    pub(crate) fn space_usage(&self) -> PerFieldSpaceUsage {
        self.fast_fields_composite.space_usage()
    }

    fn fast_field_data(&self, field: Field, idx: usize) -> crate::Result<FileSlice> {
        self.fast_fields_composite
            .open_read_with_idx(field, idx)
            .ok_or_else(|| {
                let field_name = self.schema.get_field_entry(field).name();
                TantivyError::SchemaError(format!("Field({}) data was not found", field_name))
            })
    }

    fn check_type(
        &self,
        field: Field,
        expected_fast_type: FastType,
        expected_cardinality: Cardinality,
    ) -> crate::Result<()> {
        let field_entry = self.schema.get_field_entry(field);
        let (fast_type, cardinality) =
            type_and_cardinality(field_entry.field_type()).ok_or_else(|| {
                crate::TantivyError::SchemaError(format!(
                    "Field {:?} is not a fast field.",
                    field_entry.name()
                ))
            })?;
        if fast_type != expected_fast_type {
            return Err(crate::TantivyError::SchemaError(format!(
                "Field {:?} is of type {:?}, expected {:?}.",
                field_entry.name(),
                fast_type,
                expected_fast_type
            )));
        }
        if cardinality != expected_cardinality {
            return Err(crate::TantivyError::SchemaError(format!(
                "Field {:?} is of cardinality {:?}, expected {:?}.",
                field_entry.name(),
                cardinality,
                expected_cardinality
            )));
        }
        Ok(())
    }

    pub(crate) fn typed_fast_field_reader<TFastValue: FastValue>(
        &self,
        field: Field,
    ) -> crate::Result<DynamicFastFieldReader<TFastValue>> {
        let fast_field_slice = self.fast_field_data(field, 0)?;
        DynamicFastFieldReader::open(fast_field_slice)
    }

    pub(crate) fn typed_fast_field_multi_reader<TFastValue: FastValue>(
        &self,
        field: Field,
    ) -> crate::Result<MultiValuedFastFieldReader<TFastValue>> {
        let idx_reader = self.typed_fast_field_reader(field)?;
        let fast_field_slice_vals = self.fast_field_data(field, 1)?;
        let vals_reader: BitpackedFastFieldReader<TFastValue> =
            BitpackedFastFieldReader::open(fast_field_slice_vals)?;
        Ok(MultiValuedFastFieldReader::open(idx_reader, vals_reader))
    }

    /// Returns the `u64` fast field reader reader associated to `field`.
    ///
    /// If `field` is not a u64 fast field, this method returns an Error.
    pub fn u64(&self, field: Field) -> crate::Result<DynamicFastFieldReader<u64>> {
        self.check_type(field, FastType::U64, Cardinality::SingleValue)?;
        self.typed_fast_field_reader(field)
    }

    /// Returns the `u64` fast field reader reader associated to `field`, regardless of whether the given
    /// field is effectively of type `u64` or not.
    ///
    /// If not, the fastfield reader will returns the u64-value associated to the original FastValue.
    pub fn u64_lenient(&self, field: Field) -> crate::Result<DynamicFastFieldReader<u64>> {
        self.typed_fast_field_reader(field)
    }

    /// Returns the `i64` fast field reader reader associated to `field`.
    ///
    /// If `field` is not a i64 fast field, this method returns an Error.
    pub fn i64(&self, field: Field) -> crate::Result<impl FastFieldReader<i64>> {
        self.check_type(field, FastType::I64, Cardinality::SingleValue)?;
        self.typed_fast_field_reader(field)
    }

    /// Returns the `i64` fast field reader reader associated to `field`.
    ///
    /// If `field` is not a i64 fast field, this method returns an Error.
    pub fn date(&self, field: Field) -> crate::Result<impl FastFieldReader<crate::DateTime>> {
        self.check_type(field, FastType::Date, Cardinality::SingleValue)?;
        self.typed_fast_field_reader(field)
    }

    /// Returns the `f64` fast field reader reader associated to `field`.
    ///
    /// If `field` is not a f64 fast field, this method returns an Error.
    pub fn f64(&self, field: Field) -> crate::Result<impl FastFieldReader<f64>> {
        self.check_type(field, FastType::F64, Cardinality::SingleValue)?;
        self.typed_fast_field_reader(field)
    }

    /// Returns a `u64s` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a u64 multi-valued fast field, this method returns an Error.
    pub fn u64s(&self, field: Field) -> crate::Result<MultiValuedFastFieldReader<u64>> {
        self.check_type(field, FastType::U64, Cardinality::MultiValues)?;
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns a `u64s` multi-valued fast field reader reader associated to `field`, regardless of whether the given
    /// field is effectively of type `u64` or not.
    ///
    /// If `field` is not a u64 multi-valued fast field, this method returns an Error.
    pub fn u64s_lenient(&self, field: Field) -> crate::Result<MultiValuedFastFieldReader<u64>> {
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns a `i64s` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a i64 multi-valued fast field, this method returns an Error.
    pub fn i64s(&self, field: Field) -> crate::Result<MultiValuedFastFieldReader<i64>> {
        self.check_type(field, FastType::I64, Cardinality::MultiValues)?;
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns a `f64s` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a f64 multi-valued fast field, this method returns an Error.
    pub fn f64s(&self, field: Field) -> crate::Result<MultiValuedFastFieldReader<f64>> {
        self.check_type(field, FastType::F64, Cardinality::MultiValues)?;
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns a `crate::DateTime` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a `crate::DateTime` multi-valued fast field, this method returns an Error.
    pub fn dates(
        &self,
        field: Field,
    ) -> crate::Result<MultiValuedFastFieldReader<crate::DateTime>> {
        self.check_type(field, FastType::Date, Cardinality::MultiValues)?;
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns the `bytes` fast field reader associated to `field`.
    ///
    /// If `field` is not a bytes fast field, returns an Error.
    pub fn bytes(&self, field: Field) -> crate::Result<BytesFastFieldReader> {
        let field_entry = self.schema.get_field_entry(field);
        if let FieldType::Bytes(bytes_option) = field_entry.field_type() {
            if !bytes_option.is_fast() {
                return Err(crate::TantivyError::SchemaError(format!(
                    "Field {:?} is not a fast field.",
                    field_entry.name()
                )));
            }
            let fast_field_idx_file = self.fast_field_data(field, 0)?;
            let idx_reader = BitpackedFastFieldReader::open(fast_field_idx_file)?;
            let data = self.fast_field_data(field, 1)?;
            BytesFastFieldReader::open(idx_reader, data)
        } else {
            Err(FastFieldNotAvailableError::new(field_entry).into())
        }
    }
}
<commit_msg>use concrete return type, fixes #1084<commit_after>use crate::common::CompositeFile;
use crate::directory::FileSlice;
use crate::fastfield::MultiValuedFastFieldReader;
use crate::fastfield::{BitpackedFastFieldReader, FastFieldNotAvailableError};
use crate::fastfield::{BytesFastFieldReader, FastValue};
use crate::schema::{Cardinality, Field, FieldType, Schema};
use crate::space_usage::PerFieldSpaceUsage;
use crate::TantivyError;

use super::reader::DynamicFastFieldReader;

/// Provides access to all of the BitpackedFastFieldReader.
///
/// Internally, `FastFieldReaders` have preloaded fast field readers,
/// and just wraps several `HashMap`.
#[derive(Clone)]
pub struct FastFieldReaders {
    schema: Schema,
    fast_fields_composite: CompositeFile,
}
#[derive(Eq, PartialEq, Debug)]
enum FastType {
    I64,
    U64,
    F64,
    Date,
}

fn type_and_cardinality(field_type: &FieldType) -> Option<(FastType, Cardinality)> {
    match field_type {
        FieldType::U64(options) => options
            .get_fastfield_cardinality()
            .map(|cardinality| (FastType::U64, cardinality)),
        FieldType::I64(options) => options
            .get_fastfield_cardinality()
            .map(|cardinality| (FastType::I64, cardinality)),
        FieldType::F64(options) => options
            .get_fastfield_cardinality()
            .map(|cardinality| (FastType::F64, cardinality)),
        FieldType::Date(options) => options
            .get_fastfield_cardinality()
            .map(|cardinality| (FastType::Date, cardinality)),
        FieldType::HierarchicalFacet(_) => Some((FastType::U64, Cardinality::MultiValues)),
        _ => None,
    }
}

impl FastFieldReaders {
    pub(crate) fn new(schema: Schema, fast_fields_composite: CompositeFile) -> FastFieldReaders {
        FastFieldReaders {
            schema,
            fast_fields_composite,
        }
    }

    pub(crate) fn space_usage(&self) -> PerFieldSpaceUsage {
        self.fast_fields_composite.space_usage()
    }

    fn fast_field_data(&self, field: Field, idx: usize) -> crate::Result<FileSlice> {
        self.fast_fields_composite
            .open_read_with_idx(field, idx)
            .ok_or_else(|| {
                let field_name = self.schema.get_field_entry(field).name();
                TantivyError::SchemaError(format!("Field({}) data was not found", field_name))
            })
    }

    fn check_type(
        &self,
        field: Field,
        expected_fast_type: FastType,
        expected_cardinality: Cardinality,
    ) -> crate::Result<()> {
        let field_entry = self.schema.get_field_entry(field);
        let (fast_type, cardinality) =
            type_and_cardinality(field_entry.field_type()).ok_or_else(|| {
                crate::TantivyError::SchemaError(format!(
                    "Field {:?} is not a fast field.",
                    field_entry.name()
                ))
            })?;
        if fast_type != expected_fast_type {
            return Err(crate::TantivyError::SchemaError(format!(
                "Field {:?} is of type {:?}, expected {:?}.",
                field_entry.name(),
                fast_type,
                expected_fast_type
            )));
        }
        if cardinality != expected_cardinality {
            return Err(crate::TantivyError::SchemaError(format!(
                "Field {:?} is of cardinality {:?}, expected {:?}.",
                field_entry.name(),
                cardinality,
                expected_cardinality
            )));
        }
        Ok(())
    }

    pub(crate) fn typed_fast_field_reader<TFastValue: FastValue>(
        &self,
        field: Field,
    ) -> crate::Result<DynamicFastFieldReader<TFastValue>> {
        let fast_field_slice = self.fast_field_data(field, 0)?;
        DynamicFastFieldReader::open(fast_field_slice)
    }

    pub(crate) fn typed_fast_field_multi_reader<TFastValue: FastValue>(
        &self,
        field: Field,
    ) -> crate::Result<MultiValuedFastFieldReader<TFastValue>> {
        let idx_reader = self.typed_fast_field_reader(field)?;
        let fast_field_slice_vals = self.fast_field_data(field, 1)?;
        let vals_reader: BitpackedFastFieldReader<TFastValue> =
            BitpackedFastFieldReader::open(fast_field_slice_vals)?;
        Ok(MultiValuedFastFieldReader::open(idx_reader, vals_reader))
    }

    /// Returns the `u64` fast field reader reader associated to `field`.
    ///
    /// If `field` is not a u64 fast field, this method returns an Error.
    pub fn u64(&self, field: Field) -> crate::Result<DynamicFastFieldReader<u64>> {
        self.check_type(field, FastType::U64, Cardinality::SingleValue)?;
        self.typed_fast_field_reader(field)
    }

    /// Returns the `u64` fast field reader reader associated to `field`, regardless of whether the given
    /// field is effectively of type `u64` or not.
    ///
    /// If not, the fastfield reader will returns the u64-value associated to the original FastValue.
    pub fn u64_lenient(&self, field: Field) -> crate::Result<DynamicFastFieldReader<u64>> {
        self.typed_fast_field_reader(field)
    }

    /// Returns the `i64` fast field reader reader associated to `field`.
    ///
    /// If `field` is not a i64 fast field, this method returns an Error.
    pub fn i64(&self, field: Field) -> crate::Result<DynamicFastFieldReader<i64>> {
        self.check_type(field, FastType::I64, Cardinality::SingleValue)?;
        self.typed_fast_field_reader(field)
    }

    /// Returns the `i64` fast field reader reader associated to `field`.
    ///
    /// If `field` is not a i64 fast field, this method returns an Error.
    pub fn date(&self, field: Field) -> crate::Result<DynamicFastFieldReader<crate::DateTime>> {
        self.check_type(field, FastType::Date, Cardinality::SingleValue)?;
        self.typed_fast_field_reader(field)
    }

    /// Returns the `f64` fast field reader reader associated to `field`.
    ///
    /// If `field` is not a f64 fast field, this method returns an Error.
    pub fn f64(&self, field: Field) -> crate::Result<DynamicFastFieldReader<f64>> {
        self.check_type(field, FastType::F64, Cardinality::SingleValue)?;
        self.typed_fast_field_reader(field)
    }

    /// Returns a `u64s` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a u64 multi-valued fast field, this method returns an Error.
    pub fn u64s(&self, field: Field) -> crate::Result<MultiValuedFastFieldReader<u64>> {
        self.check_type(field, FastType::U64, Cardinality::MultiValues)?;
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns a `u64s` multi-valued fast field reader reader associated to `field`, regardless of whether the given
    /// field is effectively of type `u64` or not.
    ///
    /// If `field` is not a u64 multi-valued fast field, this method returns an Error.
    pub fn u64s_lenient(&self, field: Field) -> crate::Result<MultiValuedFastFieldReader<u64>> {
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns a `i64s` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a i64 multi-valued fast field, this method returns an Error.
    pub fn i64s(&self, field: Field) -> crate::Result<MultiValuedFastFieldReader<i64>> {
        self.check_type(field, FastType::I64, Cardinality::MultiValues)?;
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns a `f64s` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a f64 multi-valued fast field, this method returns an Error.
    pub fn f64s(&self, field: Field) -> crate::Result<MultiValuedFastFieldReader<f64>> {
        self.check_type(field, FastType::F64, Cardinality::MultiValues)?;
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns a `crate::DateTime` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a `crate::DateTime` multi-valued fast field, this method returns an Error.
    pub fn dates(
        &self,
        field: Field,
    ) -> crate::Result<MultiValuedFastFieldReader<crate::DateTime>> {
        self.check_type(field, FastType::Date, Cardinality::MultiValues)?;
        self.typed_fast_field_multi_reader(field)
    }

    /// Returns the `bytes` fast field reader associated to `field`.
    ///
    /// If `field` is not a bytes fast field, returns an Error.
    pub fn bytes(&self, field: Field) -> crate::Result<BytesFastFieldReader> {
        let field_entry = self.schema.get_field_entry(field);
        if let FieldType::Bytes(bytes_option) = field_entry.field_type() {
            if !bytes_option.is_fast() {
                return Err(crate::TantivyError::SchemaError(format!(
                    "Field {:?} is not a fast field.",
                    field_entry.name()
                )));
            }
            let fast_field_idx_file = self.fast_field_data(field, 0)?;
            let idx_reader = BitpackedFastFieldReader::open(fast_field_idx_file)?;
            let data = self.fast_field_data(field, 1)?;
            BytesFastFieldReader::open(idx_reader, data)
        } else {
            Err(FastFieldNotAvailableError::new(field_entry).into())
        }
    }
}
<|endoftext|>