<commit_before>use errors::*;
use flate2::FlateReadExt;
use futures::Stream;
use futures::future::{BoxFuture, Future, ok};
use futures_cpupool::CpuPool;
use hyper::{self, Method, StatusCode};
use hyper::header::{ContentEncoding, ContentLength, Encoding};
use hyper::server::{Request, Response, Service};
use reproto_repository::{Checksum, Objects, to_checksum};
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::sync::{Arc, Mutex};
use tempfile;

static CHECKSUM_MISMATCH: &'static [u8] = b"Checksum Mismatch";

/// ## Read the contents of the file into a byte-vector
fn read_contents<P: AsRef<Path>>(path: P) -> Result<Vec<u8>> {
    let mut f = File::open(path)?;
    let mut content = Vec::new();
    f.read_to_end(&mut content)?;
    Ok(content)
}

pub struct ReprotoService {
    pub max_file_size: u64,
    pub pool: Arc<CpuPool>,
    pub objects: Arc<Mutex<Box<Objects>>>,
}

impl ReprotoService {
    fn no_encoding(input: &File) -> Result<Box<Read>> {
        Ok(Box::new(input.try_clone()?))
    }

    fn gzip_encoding(input: &File) -> Result<Box<Read>> {
        Ok(Box::new(input.try_clone()?.gz_decode()?))
    }

    fn not_found() -> Response {
        Response::new().with_status(StatusCode::NotFound)
    }

    fn get_objects(&self, path: &str) -> Result<BoxFuture<Response, Error>> {
        let objects = self.objects.clone();

        let checksum =
            Checksum::from_str(&path[..]).map_err(|_| ErrorKind::BadRequest("bad object id"))?;

        // No async I/O, use pool
        Ok(self.pool
            .spawn_fn(move || {
                let result =
                    objects.lock().map_err(|_| ErrorKind::PoisonError)?.get_object(&checksum)?;

                let path = match result {
                    Some(path) => path,
                    None => return Ok(Self::not_found()),
                };

                let bytes = read_contents(path)?;

                Ok(Response::new()
                    .with_status(StatusCode::Ok)
                    .with_header(ContentLength(bytes.len() as u64))
                    .with_body(bytes))
            })
            .boxed())
    }

    fn put_objects(&self, req: Request, path: &str) -> Result<BoxFuture<Response, Error>> {
        let checksum =
            Checksum::from_str(&path[..]).map_err(|_| ErrorKind::BadRequest("bad object id"))?;

        if let Some(len) = req.headers().get::<ContentLength>() {
            if len.0 > self.max_file_size {
                return Err(ErrorKind::BadRequest("file too large").into());
            }
        } else {
            return Err(ErrorKind::BadRequest("missing content-length").into());
        }

        let mut encoding: fn(&File) -> Result<Box<Read>> = Self::no_encoding;

        if let Some(h) = req.headers().get::<ContentEncoding>() {
            // client encoded as gzip
            if h.0.iter().find(|encoding| **encoding == Encoding::Gzip).is_some() {
                encoding = Self::gzip_encoding;
            }
        }

        info!("Creating temporary file");
        /// TODO: make temporary
        let tmp = tempfile::tempfile()?;

        let pool = self.pool.clone();

        /// Write file in chunks as it becomes available
        let body = req.body()
            .map_err::<Error, _>(Into::into)
            .fold((pool, tmp), |(pool, mut tmp), chunk| {
                /// Write chunks on cpu-pool
                let write = pool.spawn_fn(move || {
                    tmp.write_all(chunk.as_ref())?;
                    Ok(tmp) as Result<File>
                });

                write.map(|tmp| (pool, tmp))
            })
            .map(|(_, tmp)| tmp);

        let pool = self.pool.clone();
        let objects = self.objects.clone();

        let upload = body.and_then(move |mut tmp| {
            pool.spawn_fn(move || {
                tmp.seek(SeekFrom::Start(0))?;

                let mut checksum_read = encoding(&tmp)?;
                let actual = to_checksum(&mut checksum_read)?;

                if actual != checksum {
                    info!("{} != {}", actual, checksum);

                    return Ok(Response::new()
                        .with_body(CHECKSUM_MISMATCH)
                        .with_status(StatusCode::BadRequest));
                }

                info!("Uploading object: {}", checksum);

                let mut read = encoding(&tmp)?;

                objects.lock()
                    .map_err(|_| ErrorKind::PoisonError)?
                    .put_object(&checksum, &mut read)?;

                Ok(Response::new().with_status(StatusCode::Ok))
            })
        });

        Ok(upload.boxed())
    }

    fn inner_call(&self, req: Request, path: &str) -> Result<BoxFuture<Response, Error>> {
        if let Some(len) = path.find('/') {
            match (req.method(), &path[0..len]) {
                (&Method::Get, "objects") => return self.get_objects(&path[len + 1..]),
                (&Method::Put, "objects") => return self.put_objects(req, &path[len + 1..]),
                _ => return Ok(ok(Self::not_found()).boxed()),
            }
        }

        Ok(ok(Self::not_found()).boxed())
    }

    fn handle_error(e: Error) -> Response {
        match *e.kind() {
            ErrorKind::BadRequest(ref message) => {
                return Response::new()
                    .with_status(StatusCode::BadRequest)
                    .with_header(ContentLength(message.len() as u64))
                    .with_body(*message)
            }
            _ => {
                return Response::new().with_status(StatusCode::InternalServerError);
            }
        }
    }
}

impl Service for ReprotoService {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = BoxFuture<Response, hyper::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let mut path = String::from(req.path());

        // remove leading slash
        if let Some(len) = path.find('/') {
            path.drain(..len + 1);
        }

        self.inner_call(req, path.as_str())
            .unwrap_or_else(|e| ok(Self::handle_error(e)).boxed())
            .or_else(|e| ok(Self::handle_error(e)))
            .boxed()
    }
}
<commit_msg>server: extract pick_encoding<commit_after>use errors::*;
use flate2::FlateReadExt;
use futures::Stream;
use futures::future::{BoxFuture, Future, ok};
use futures_cpupool::CpuPool;
use hyper::{self, Method, StatusCode};
use hyper::header::{ContentEncoding, ContentLength, Encoding, Headers};
use hyper::server::{Request, Response, Service};
use reproto_repository::{Checksum, Objects, to_checksum};
use std::fs::File;
use std::io::{Seek, SeekFrom};
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::sync::{Arc, Mutex};
use tempfile;

static CHECKSUM_MISMATCH: &'static [u8] = b"Checksum Mismatch";

/// ## Read the contents of the file into a byte-vector
fn read_contents<P: AsRef<Path>>(path: P) -> Result<Vec<u8>> {
    let mut f = File::open(path)?;
    let mut content = Vec::new();
    f.read_to_end(&mut content)?;
    Ok(content)
}

pub struct ReprotoService {
    pub max_file_size: u64,
    pub pool: Arc<CpuPool>,
    pub objects: Arc<Mutex<Box<Objects>>>,
}

impl ReprotoService {
    fn no_encoding(input: &File) -> Result<Box<Read>> {
        Ok(Box::new(input.try_clone()?))
    }

    fn gzip_encoding(input: &File) -> Result<Box<Read>> {
        Ok(Box::new(input.try_clone()?.gz_decode()?))
    }

    fn pick_encoding(headers: &Headers) -> fn(&File) -> Result<Box<Read>> {
        if let Some(h) = headers.get::<ContentEncoding>() {
            // client encoded as gzip
            if h.0.iter().find(|encoding| **encoding == Encoding::Gzip).is_some() {
                return Self::gzip_encoding;
            }
        }

        Self::no_encoding
    }

    fn not_found() -> Response {
        Response::new().with_status(StatusCode::NotFound)
    }

    fn get_objects(&self, path: &str) -> Result<BoxFuture<Response, Error>> {
        let objects = self.objects.clone();

        let checksum =
            Checksum::from_str(&path[..]).map_err(|_| ErrorKind::BadRequest("bad object id"))?;

        // No async I/O, use pool
        Ok(self.pool
            .spawn_fn(move || {
                let result =
                    objects.lock().map_err(|_| ErrorKind::PoisonError)?.get_object(&checksum)?;

                let path = match result {
                    Some(path) => path,
                    None => return Ok(Self::not_found()),
                };

                let bytes = read_contents(path)?;

                Ok(Response::new()
                    .with_status(StatusCode::Ok)
                    .with_header(ContentLength(bytes.len() as u64))
                    .with_body(bytes))
            })
            .boxed())
    }

    fn put_objects(&self, req: Request, path: &str) -> Result<BoxFuture<Response, Error>> {
        let checksum =
            Checksum::from_str(&path[..]).map_err(|_| ErrorKind::BadRequest("bad object id"))?;

        if let Some(len) = req.headers().get::<ContentLength>() {
            if len.0 > self.max_file_size {
                return Err(ErrorKind::BadRequest("file too large").into());
            }
        } else {
            return Err(ErrorKind::BadRequest("missing content-length").into());
        }

        let encoding = Self::pick_encoding(req.headers());

        info!("Creating temporary file");
        /// TODO: make temporary
        let tmp = tempfile::tempfile()?;

        let pool = self.pool.clone();

        /// Write file in chunks as it becomes available
        let body = req.body()
            .map_err::<Error, _>(Into::into)
            .fold((pool, tmp), |(pool, mut tmp), chunk| {
                /// Write chunks on cpu-pool
                let write = pool.spawn_fn(move || {
                    tmp.write_all(chunk.as_ref())?;
                    Ok(tmp) as Result<File>
                });

                write.map(|tmp| (pool, tmp))
            })
            .map(|(_, tmp)| tmp);

        let pool = self.pool.clone();
        let objects = self.objects.clone();

        let upload = body.and_then(move |mut tmp| {
            pool.spawn_fn(move || {
                tmp.seek(SeekFrom::Start(0))?;

                let mut checksum_read = encoding(&tmp)?;
                let actual = to_checksum(&mut checksum_read)?;

                if actual != checksum {
                    info!("{} != {}", actual, checksum);

                    return Ok(Response::new()
                        .with_body(CHECKSUM_MISMATCH)
                        .with_status(StatusCode::BadRequest));
                }

                info!("Uploading object: {}", checksum);

                let mut read = encoding(&tmp)?;

                objects.lock()
                    .map_err(|_| ErrorKind::PoisonError)?
                    .put_object(&checksum, &mut read)?;

                Ok(Response::new().with_status(StatusCode::Ok))
            })
        });

        Ok(upload.boxed())
    }

    fn inner_call(&self, req: Request, path: &str) -> Result<BoxFuture<Response, Error>> {
        if let Some(len) = path.find('/') {
            match (req.method(), &path[0..len]) {
                (&Method::Get, "objects") => return self.get_objects(&path[len + 1..]),
                (&Method::Put, "objects") => return self.put_objects(req, &path[len + 1..]),
                _ => return Ok(ok(Self::not_found()).boxed()),
            }
        }

        Ok(ok(Self::not_found()).boxed())
    }

    fn handle_error(e: Error) -> Response {
        match *e.kind() {
            ErrorKind::BadRequest(ref message) => {
                return Response::new()
                    .with_status(StatusCode::BadRequest)
                    .with_header(ContentLength(message.len() as u64))
                    .with_body(*message)
            }
            _ => {
                return Response::new().with_status(StatusCode::InternalServerError);
            }
        }
    }
}

impl Service for ReprotoService {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = BoxFuture<Response, hyper::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let mut path = String::from(req.path());

        // remove leading slash
        if let Some(len) = path.find('/') {
            path.drain(..len + 1);
        }

        self.inner_call(req, path.as_str())
            .unwrap_or_else(|e| ok(Self::handle_error(e)).boxed())
            .or_else(|e| ok(Self::handle_error(e)))
            .boxed()
    }
}
<|endoftext|>


<commit_before>use card_strategy::CardStrategy;

use card::Card;
use game_status::GameStatus;
use player::PlayerName;

use std::collections::BTreeMap;

#[derive(Debug)]
pub struct MyCardStrategy;

impl MyCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus, player_name: &PlayerName) -> (i32, i32, i32, i32) {
        let card_penalty_to_me = MyCardStrategy::card_penalty_to_me(card, game_status, player_name);
        let card_penalty = 0 - MyCardStrategy::card_penalty(card, game_status);
        let trouble = MyCardStrategy::trouble_score(card, game_status);
        let card_rank = 0 - (u32::from(card.rank) as i32);
        (card_penalty_to_me, card_penalty, trouble, card_rank)
    }

    fn card_penalty(card: &Card, game_status: &GameStatus) -> i32 {
        game_status.round_parameters.card_points.get(card)
            .map(|penalty| penalty.clone())
            .unwrap_or_default()
    }

    fn card_penalty_to_me(card: &Card, game_status: &GameStatus, player_name: &PlayerName) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            MyCardStrategy::card_penalty(card, game_status)
        } else {
            0
        }
    }

    fn trouble_score(card: &Card, game_status: &GameStatus) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            u32::from(card.rank) as i32
        } else {
            0
        }
    }

    fn will_win_deal(card: &Card, game_status: &GameStatus) -> bool {
        game_status.my_in_progress_deal.as_ref().and_then(|deal|
            deal.suit.and_then(|suit|
                deal.deal_cards.iter()
                    .map(|deal_card| deal_card.card)
                    .filter(|card| card.suit == suit)
                    .max()
                    .map(|winning_card| card.suit == suit && card.rank > winning_card.rank))).unwrap_or(true)
    }
}

impl CardStrategy for MyCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        // Need to order cards by potential to win lowest penalty hands
        let mut initial_hand: Vec<&'a Card> = game_status.my_initial_hand.iter().collect();
        initial_hand.reverse();
        initial_hand.into_iter().take(3).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let current_suit = game_status.my_in_progress_deal.as_ref().and_then(|deal| deal.suit);
        let mut valid_cards: Vec<&'a Card> = game_status.my_current_hand.iter().filter(|card| Some(card.suit) == current_suit).collect();

        if valid_cards.is_empty() {
            valid_cards.extend(&game_status.my_current_hand);
        }

        let scored_cards = valid_cards.into_iter()
            .map(|card| ((MyCardStrategy::score_card(card, game_status, player_name), card), card))
            .collect::<BTreeMap<((i32, i32, i32, i32), &Card), &Card>>();

        scored_cards.values().next().expect("No valid cards to play!")
    }

}<commit_msg>cleanup<commit_after>use card_strategy::CardStrategy;

use card::Card;
use game_status::GameStatus;
use player::PlayerName;

use std::collections::BTreeMap;

#[derive(Debug)]
pub struct MyCardStrategy;

impl MyCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus, player_name: &PlayerName) -> (i32, i32, i32, i32) {
        let card_penalty_to_me = MyCardStrategy::card_penalty_to_me(card, game_status, player_name);
        let card_penalty = 0 - MyCardStrategy::card_penalty(card, game_status);
        let trouble = MyCardStrategy::trouble_score(card, game_status);
        let card_rank = 0 - (u32::from(card.rank) as i32);
        (card_penalty_to_me, card_penalty, trouble, card_rank)
    }

    fn card_penalty(card: &Card, game_status: &GameStatus) -> i32 {
        game_status.round_parameters.card_points.get(card)
            .map(|penalty| *penalty)
            .unwrap_or_default()
    }

    fn card_penalty_to_me(card: &Card, game_status: &GameStatus, player_name: &PlayerName) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            MyCardStrategy::card_penalty(card, game_status)
        } else {
            0
        }
    }

    fn trouble_score(card: &Card, game_status: &GameStatus) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            u32::from(card.rank) as i32
        } else {
            0
        }
    }

    fn will_win_deal(card: &Card, game_status: &GameStatus) -> bool {
        game_status.my_in_progress_deal.as_ref().and_then(|deal|
            deal.suit.and_then(|suit|
                deal.deal_cards.iter()
                    .map(|deal_card| deal_card.card)
                    .filter(|card| card.suit == suit)
                    .max()
                    .map(|winning_card| card.suit == suit && card.rank > winning_card.rank))).unwrap_or(true)
    }
}

impl CardStrategy for MyCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        // Need to order cards by potential to win lowest penalty hands
        let mut initial_hand: Vec<&'a Card> = game_status.my_initial_hand.iter().collect();
        initial_hand.reverse();
        initial_hand.into_iter().take(3).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let current_suit = game_status.my_in_progress_deal.as_ref().and_then(|deal| deal.suit);
        let mut valid_cards: Vec<&'a Card> = game_status.my_current_hand.iter().filter(|card| Some(card.suit) == current_suit).collect();

        if valid_cards.is_empty() {
            valid_cards.extend(&game_status.my_current_hand);
        }

        valid_cards.into_iter()
            .map(|card| ((MyCardStrategy::score_card(card, game_status, player_name), card), card))
            .collect::<BTreeMap<((i32, i32, i32, i32), &Card), &Card>>()
            .values()
            .next()
            .expect("No valid cards to play!")
    }

}<|endoftext|>


<commit_before>use std::sync::atomic::Ordering::{Acquire, Release, Relaxed};
use std::ptr;

use mem::epoch::{self, Atomic, Owned};

/// Treiber's lock-free stack.
///
/// Usable with any number of producers and consumers.
#[derive(Debug)]
pub struct TreiberStack<T> {
    head: Atomic<Node<T>>,
}

#[derive(Debug)]
struct Node<T> {
    data: T,
    next: Atomic<Node<T>>,
}

impl<T> TreiberStack<T> {
    /// Create a new, empty stack.
    pub fn new() -> TreiberStack<T> {
        TreiberStack {
            head: Atomic::null()
        }
    }

    /// Push `t` on top of the stack.
    pub fn push(&self, t: T) {
        let mut n = Owned::new(Node {
            data: t,
            next: Atomic::null()
        });
        let guard = epoch::pin();
        loop {
            let head = self.head.load(Relaxed, &guard);
            n.next.store_shared(head, Relaxed);
            match self.head.cas_and_ref(head, n, Release, &guard) {
                Ok(_) => break,
                Err(owned) => n = owned,
            }
        }
    }

    /// Attempt to pop the top element of the stack.
    ///
    /// Returns `None` if the stack is observed to be empty.
    pub fn pop(&self) -> Option<T> {
        let guard = epoch::pin();
        loop {
            match self.head.load(Acquire, &guard) {
                Some(head) => {
                    let next = head.next.load(Relaxed, &guard);
                    if self.head.cas_shared(Some(head), next, Release) {
                        unsafe {
                            guard.unlinked(head);
                            return Some(ptr::read(&(*head).data))
                        }
                    }
                }
                None => return None
            }
        }
    }

    /// Check if this queue is empty.
    pub fn is_empty(&self) -> bool {
        let guard = epoch::pin();
        self.head.load(Acquire, &guard).is_none()
    }
}

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

    #[test]
    fn is_empty() {
        let q: TreiberStack<i64> = TreiberStack::new();
        assert!(q.is_empty());
        q.push(20);
        q.push(20);
        assert!(!q.is_empty());
        assert!(!q.is_empty());
        assert!(q.pop().is_some());
        assert!(q.pop().is_some());
        assert!(q.is_empty());
        q.push(25);
        assert!(!q.is_empty());
    }
}
<commit_msg>rename pop to try_pop with deprecation warning (#69)<commit_after>use std::sync::atomic::Ordering::{Acquire, Release, Relaxed};
use std::ptr;

use mem::epoch::{self, Atomic, Owned};

/// Treiber's lock-free stack.
///
/// Usable with any number of producers and consumers.
#[derive(Debug)]
pub struct TreiberStack<T> {
    head: Atomic<Node<T>>,
}

#[derive(Debug)]
struct Node<T> {
    data: T,
    next: Atomic<Node<T>>,
}

impl<T> TreiberStack<T> {
    /// Create a new, empty stack.
    pub fn new() -> TreiberStack<T> {
        TreiberStack { head: Atomic::null() }
    }

    /// Push `t` on top of the stack.
    pub fn push(&self, t: T) {
        let mut n = Owned::new(Node {
            data: t,
            next: Atomic::null(),
        });
        let guard = epoch::pin();
        loop {
            let head = self.head.load(Relaxed, &guard);
            n.next.store_shared(head, Relaxed);
            match self.head.cas_and_ref(head, n, Release, &guard) {
                Ok(_) => break,
                Err(owned) => n = owned,
            }
        }
    }

    /// Attempt to pop the top element of the stack.
    /// **Deprecated method**, use try_pop
    ///
    /// Returns `None` if the stack is observed to be empty.
    #[cfg_attr(any(feature="beta", feature="nightly"), deprecated(note="The pop method has been renamed to try_pop for consistency with other collections."))]
    pub fn pop(&self) -> Option<T> {
        self.try_pop()
    }

    /// Attempt to pop the top element of the stack.
    ///
    /// Returns `None` if the stack is observed to be empty.
    pub fn try_pop(&self) -> Option<T> {
        let guard = epoch::pin();
        loop {
            match self.head.load(Acquire, &guard) {
                Some(head) => {
                    let next = head.next.load(Relaxed, &guard);
                    if self.head.cas_shared(Some(head), next, Release) {
                        unsafe {
                            guard.unlinked(head);
                            return Some(ptr::read(&(*head).data));
                        }
                    }
                }
                None => return None,
            }
        }
    }

    /// Check if this queue is empty.
    pub fn is_empty(&self) -> bool {
        let guard = epoch::pin();
        self.head.load(Acquire, &guard).is_none()
    }
}

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

    #[test]
    fn is_empty() {
        let q: TreiberStack<i64> = TreiberStack::new();
        assert!(q.is_empty());
        q.push(20);
        q.push(20);
        assert!(!q.is_empty());
        assert!(!q.is_empty());
        assert!(q.try_pop().is_some());
        assert!(q.try_pop().is_some());
        assert!(q.is_empty());
        q.push(25);
        assert!(!q.is_empty());
    }
}
<|endoftext|>


<commit_before><commit_msg>Refactor the ConstantOrigin shape to the query module.<commit_after>use na::{RealField, Unit};

use crate::math::{Isometry, Point, Vector};
use crate::shape::SupportMap;

/// A support mapping that is always equal to the origin, independently from its transform.
pub struct ConstantOrigin;

impl<N: RealField> SupportMap<N> for ConstantOrigin {
    #[inline]
    fn support_point(&self, _: &Isometry<N>, _: &Vector<N>) -> Point<N> {
        Point::origin()
    }

    #[inline]
    fn support_point_toward(&self, _: &Isometry<N>, _: &Unit<Vector<N>>) -> Point<N> {
        Point::origin()
    }
}

/// The Minkowski sum of a shape and a ball.
pub struct DilatedShape<'a, N: RealField, S: ?Sized + SupportMap<N>> {
    /// The shape involved in the Minkowski sum.
    pub shape: &'a S,
    /// The radius of the ball involved in the Minkoski sum.
    pub radius: N,
}

impl<'a, N: RealField, S: ?Sized + SupportMap<N>> SupportMap<N> for DilatedShape<'a, N, S> {
    #[inline]
    fn support_point(&self, m: &Isometry<N>, dir: &Vector<N>) -> Point<N> {
        self.support_point_toward(m, &Unit::new_normalize(*dir))
    }

    #[inline]
    fn support_point_toward(&self, m: &Isometry<N>, dir: &Unit<Vector<N>>) -> Point<N> {
        self.shape.support_point_toward(m, dir) + **dir * self.radius
    }
}<|endoftext|>


<commit_before>use std::{
    io::{self, ErrorKind},
    net::SocketAddr,
    sync::Arc,
    time::Duration,
};

use byte_string::ByteStr;
use kcp::{Error as KcpError, KcpResult};
use log::{debug, error, trace};
use tokio::{
    net::{ToSocketAddrs, UdpSocket},
    sync::mpsc,
    task::JoinHandle,
    time,
};

use crate::{config::KcpConfig, session::KcpSessionManager, stream::KcpStream};

pub struct KcpListener {
    udp: Arc<UdpSocket>,
    accept_rx: mpsc::Receiver<(KcpStream, SocketAddr)>,
    task_watcher: JoinHandle<()>,
}

impl Drop for KcpListener {
    fn drop(&mut self) {
        self.task_watcher.abort();
    }
}

impl KcpListener {
    /// Create an `KcpListener` bound to `addr`
    pub async fn bind<A: ToSocketAddrs>(config: KcpConfig, addr: A) -> KcpResult<KcpListener> {
        let udp = UdpSocket::bind(addr).await?;
        let udp = Arc::new(udp);
        let server_udp = udp.clone();

        let (accept_tx, accept_rx) = mpsc::channel(1024 /* backlogs */);
        let task_watcher = tokio::spawn(async move {
            let (close_tx, mut close_rx) = mpsc::channel(64);

            let mut sessions = KcpSessionManager::new();
            let mut packet_buffer = [0u8; 65536];
            loop {
                tokio::select! {
                    peer_addr = close_rx.recv() => {
                        let peer_addr = peer_addr.expect("close_tx closed unexpectly");
                        sessions.close_peer(peer_addr);
                        trace!("session peer_addr: {} removed", peer_addr);
                    }

                    recv_res = udp.recv_from(&mut packet_buffer) => {
                        match recv_res {
                            Err(err) => {
                                error!("udp.recv_from failed, error: {}", err);
                                time::sleep(Duration::from_secs(1)).await;
                            }
                            Ok((n, peer_addr)) => {
                                let packet = &mut packet_buffer[..n];

                                log::trace!("received peer: {}, {:?}", peer_addr, ByteStr::new(packet));

                                let mut conv = kcp::get_conv(packet);
                                if conv == 0 {
                                    // Allocate a conv for client.
                                    conv = sessions.alloc_conv();
                                    debug!("allocate {} conv for peer: {}", conv, peer_addr);

                                    kcp::set_conv(packet, conv);
                                }

                                let sn = kcp::get_sn(packet);

                                let session = match sessions.get_or_create(&config, conv, sn, &udp, peer_addr, &close_tx).await {
                                    Ok((s, created)) => {
                                        if created {
                                            // Created a new session, constructed a new accepted client
                                            let stream = KcpStream::with_session(s.clone());
                                            if let Err(..) = accept_tx.try_send((stream, peer_addr)) {
                                                debug!("failed to create accepted stream due to channel failure");

                                                // remove it from session
                                                sessions.close_peer(peer_addr);
                                                continue;
                                            }
                                        } else {
                                            let session_conv = s.conv().await;
                                            if session_conv != conv {
                                                debug!("received peer: {} with conv: {} not match with session conv: {}",
                                                       peer_addr,
                                                       conv,
                                                       session_conv);
                                                continue;
                                            }
                                        }

                                        s
                                    },
                                    Err(err) => {
                                        error!("failed to create session, error: {}, peer: {}, conv: {}", err, peer_addr, conv);
                                        continue;
                                    }
                                };

                                // let mut kcp = session.kcp_socket().lock().await;
                                // if let Err(err) = kcp.input(packet) {
                                //     error!("kcp.input failed, peer: {}, conv: {}, error: {}, packet: {:?}", peer_addr, conv, err, ByteStr::new(packet));
                                // }
                                session.input(packet).await;
                            }
                        }
                    }
                }
            }
        });

        Ok(KcpListener {
            udp: server_udp,
            accept_rx,
            task_watcher,
        })
    }

    /// Accept a new connected `KcpStream`
    pub async fn accept(&mut self) -> KcpResult<(KcpStream, SocketAddr)> {
        match self.accept_rx.recv().await {
            Some(s) => Ok(s),
            None => Err(KcpError::IoError(io::Error::new(
                ErrorKind::Other,
                "accept channel closed unexpectly",
            ))),
        }
    }

    /// Get the local address of the underlying socket
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.udp.local_addr()
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for KcpListener {
    fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd {
        self.udp.as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawSocket for KcpListener {
    fn as_raw_socket(&self) -> std::os::windows::prelude::RawSocket {
        self.windows.as_raw_socket()
    }
}

#[cfg(test)]
mod test {
    use super::KcpListener;
    use crate::{config::KcpConfig, stream::KcpStream};
    use futures::future;
    use tokio::io::{AsyncReadExt, AsyncWriteExt};

    #[tokio::test]
    async fn multi_echo() {
        let _ = env_logger::try_init();

        let config = KcpConfig::default();

        let mut listener = KcpListener::bind(config.clone(), "127.0.0.1:0").await.unwrap();
        let server_addr = listener.local_addr().unwrap();

        tokio::spawn(async move {
            loop {
                let (mut stream, _) = listener.accept().await.unwrap();

                tokio::spawn(async move {
                    let mut buffer = [0u8; 8192];
                    while let Ok(n) = stream.read(&mut buffer).await {
                        if n == 0 {
                            break;
                        }

                        let data = &buffer[..n];
                        stream.write_all(data).await.unwrap();
                        stream.flush().await.unwrap();
                    }
                });
            }
        });

        let mut vfut = Vec::new();

        for _ in 0..100 {
            vfut.push(async move {
                let mut stream = KcpStream::connect(&config, server_addr).await.unwrap();

                for _ in 0..20 {
                    const SEND_BUFFER: &[u8] = b"HELLO WORLD";
                    stream.write_all(SEND_BUFFER).await.unwrap();
                    stream.flush().await.unwrap();

                    let mut buffer = [0u8; 1024];
                    let n = stream.recv(&mut buffer).await.unwrap();
                    assert_eq!(SEND_BUFFER, &buffer[..n]);
                }
            });
        }

        future::join_all(vfut).await;
    }
}
<commit_msg>fix: fixed field naming<commit_after>use std::{
    io::{self, ErrorKind},
    net::SocketAddr,
    sync::Arc,
    time::Duration,
};

use byte_string::ByteStr;
use kcp::{Error as KcpError, KcpResult};
use log::{debug, error, trace};
use tokio::{
    net::{ToSocketAddrs, UdpSocket},
    sync::mpsc,
    task::JoinHandle,
    time,
};

use crate::{config::KcpConfig, session::KcpSessionManager, stream::KcpStream};

pub struct KcpListener {
    udp: Arc<UdpSocket>,
    accept_rx: mpsc::Receiver<(KcpStream, SocketAddr)>,
    task_watcher: JoinHandle<()>,
}

impl Drop for KcpListener {
    fn drop(&mut self) {
        self.task_watcher.abort();
    }
}

impl KcpListener {
    /// Create an `KcpListener` bound to `addr`
    pub async fn bind<A: ToSocketAddrs>(config: KcpConfig, addr: A) -> KcpResult<KcpListener> {
        let udp = UdpSocket::bind(addr).await?;
        let udp = Arc::new(udp);
        let server_udp = udp.clone();

        let (accept_tx, accept_rx) = mpsc::channel(1024 /* backlogs */);
        let task_watcher = tokio::spawn(async move {
            let (close_tx, mut close_rx) = mpsc::channel(64);

            let mut sessions = KcpSessionManager::new();
            let mut packet_buffer = [0u8; 65536];
            loop {
                tokio::select! {
                    peer_addr = close_rx.recv() => {
                        let peer_addr = peer_addr.expect("close_tx closed unexpectly");
                        sessions.close_peer(peer_addr);
                        trace!("session peer_addr: {} removed", peer_addr);
                    }

                    recv_res = udp.recv_from(&mut packet_buffer) => {
                        match recv_res {
                            Err(err) => {
                                error!("udp.recv_from failed, error: {}", err);
                                time::sleep(Duration::from_secs(1)).await;
                            }
                            Ok((n, peer_addr)) => {
                                let packet = &mut packet_buffer[..n];

                                log::trace!("received peer: {}, {:?}", peer_addr, ByteStr::new(packet));

                                let mut conv = kcp::get_conv(packet);
                                if conv == 0 {
                                    // Allocate a conv for client.
                                    conv = sessions.alloc_conv();
                                    debug!("allocate {} conv for peer: {}", conv, peer_addr);

                                    kcp::set_conv(packet, conv);
                                }

                                let sn = kcp::get_sn(packet);

                                let session = match sessions.get_or_create(&config, conv, sn, &udp, peer_addr, &close_tx).await {
                                    Ok((s, created)) => {
                                        if created {
                                            // Created a new session, constructed a new accepted client
                                            let stream = KcpStream::with_session(s.clone());
                                            if let Err(..) = accept_tx.try_send((stream, peer_addr)) {
                                                debug!("failed to create accepted stream due to channel failure");

                                                // remove it from session
                                                sessions.close_peer(peer_addr);
                                                continue;
                                            }
                                        } else {
                                            let session_conv = s.conv().await;
                                            if session_conv != conv {
                                                debug!("received peer: {} with conv: {} not match with session conv: {}",
                                                       peer_addr,
                                                       conv,
                                                       session_conv);
                                                continue;
                                            }
                                        }

                                        s
                                    },
                                    Err(err) => {
                                        error!("failed to create session, error: {}, peer: {}, conv: {}", err, peer_addr, conv);
                                        continue;
                                    }
                                };

                                // let mut kcp = session.kcp_socket().lock().await;
                                // if let Err(err) = kcp.input(packet) {
                                //     error!("kcp.input failed, peer: {}, conv: {}, error: {}, packet: {:?}", peer_addr, conv, err, ByteStr::new(packet));
                                // }
                                session.input(packet).await;
                            }
                        }
                    }
                }
            }
        });

        Ok(KcpListener {
            udp: server_udp,
            accept_rx,
            task_watcher,
        })
    }

    /// Accept a new connected `KcpStream`
    pub async fn accept(&mut self) -> KcpResult<(KcpStream, SocketAddr)> {
        match self.accept_rx.recv().await {
            Some(s) => Ok(s),
            None => Err(KcpError::IoError(io::Error::new(
                ErrorKind::Other,
                "accept channel closed unexpectly",
            ))),
        }
    }

    /// Get the local address of the underlying socket
    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        self.udp.local_addr()
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for KcpListener {
    fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd {
        self.udp.as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawSocket for KcpListener {
    fn as_raw_socket(&self) -> std::os::windows::prelude::RawSocket {
        self.udp.as_raw_socket()
    }
}

#[cfg(test)]
mod test {
    use super::KcpListener;
    use crate::{config::KcpConfig, stream::KcpStream};
    use futures::future;
    use tokio::io::{AsyncReadExt, AsyncWriteExt};

    #[tokio::test]
    async fn multi_echo() {
        let _ = env_logger::try_init();

        let config = KcpConfig::default();

        let mut listener = KcpListener::bind(config.clone(), "127.0.0.1:0").await.unwrap();
        let server_addr = listener.local_addr().unwrap();

        tokio::spawn(async move {
            loop {
                let (mut stream, _) = listener.accept().await.unwrap();

                tokio::spawn(async move {
                    let mut buffer = [0u8; 8192];
                    while let Ok(n) = stream.read(&mut buffer).await {
                        if n == 0 {
                            break;
                        }

                        let data = &buffer[..n];
                        stream.write_all(data).await.unwrap();
                        stream.flush().await.unwrap();
                    }
                });
            }
        });

        let mut vfut = Vec::new();

        for _ in 0..100 {
            vfut.push(async move {
                let mut stream = KcpStream::connect(&config, server_addr).await.unwrap();

                for _ in 0..20 {
                    const SEND_BUFFER: &[u8] = b"HELLO WORLD";
                    stream.write_all(SEND_BUFFER).await.unwrap();
                    stream.flush().await.unwrap();

                    let mut buffer = [0u8; 1024];
                    let n = stream.recv(&mut buffer).await.unwrap();
                    assert_eq!(SEND_BUFFER, &buffer[..n]);
                }
            });
        }

        future::join_all(vfut).await;
    }
}
<|endoftext|>


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

/// Provides access to all of the FastFieldReader.
///
/// Internally, `FastFieldReaders` have preloaded fast field readers,
/// and just wraps several `HashMap`.
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,
    ) -> crate::Result<FastFieldReaders> {
        Ok(FastFieldReaders {
            fast_fields_composite,
            schema,
        })
    }

    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<FastFieldReader<TFastValue>> {
        let fast_field_slice = self.fast_field_data(field, 0)?;
        FastFieldReader::open(fast_field_slice)
    }

    pub(crate) fn typed_fast_field_multi_reader<TFastValue: FastValue>(
        &self,
        field: Field,
    ) -> crate::Result<MultiValuedFastFieldReader<TFastValue>> {
        let fast_field_slice_idx = self.fast_field_data(field, 0)?;
        let fast_field_slice_vals = self.fast_field_data(field, 1)?;
        let idx_reader = FastFieldReader::open(fast_field_slice_idx)?;
        let vals_reader: FastFieldReader<TFastValue> =
            FastFieldReader::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 `None`.
    pub fn u64(&self, field: Field) -> crate::Result<FastFieldReader<u64>> {
        self.check_type(field, FastType::U64, 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 `None`.
    pub fn i64(&self, field: Field) -> crate::Result<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 `None`.
    pub fn date(&self, field: Field) -> crate::Result<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 `None`.
    pub fn f64(&self, field: Field) -> crate::Result<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 `None`.
    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 `i64s` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a i64 multi-valued fast field, this method returns `None`.
    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 `None`.
    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 `None`.
    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 `None`.
    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 = FastFieldReader::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>Made fast field reader clonable.<commit_after>use crate::common::CompositeFile;
use crate::directory::FileSlice;
use crate::fastfield::MultiValuedFastFieldReader;
use crate::fastfield::{BytesFastFieldReader, FastValue};
use crate::fastfield::{FastFieldNotAvailableError, FastFieldReader};
use crate::schema::{Cardinality, Field, FieldType, Schema};
use crate::space_usage::PerFieldSpaceUsage;
use crate::TantivyError;

/// Provides access to all of the FastFieldReader.
///
/// 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,
    ) -> crate::Result<FastFieldReaders> {
        Ok(FastFieldReaders {
            fast_fields_composite,
            schema,
        })
    }

    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<FastFieldReader<TFastValue>> {
        let fast_field_slice = self.fast_field_data(field, 0)?;
        FastFieldReader::open(fast_field_slice)
    }

    pub(crate) fn typed_fast_field_multi_reader<TFastValue: FastValue>(
        &self,
        field: Field,
    ) -> crate::Result<MultiValuedFastFieldReader<TFastValue>> {
        let fast_field_slice_idx = self.fast_field_data(field, 0)?;
        let fast_field_slice_vals = self.fast_field_data(field, 1)?;
        let idx_reader = FastFieldReader::open(fast_field_slice_idx)?;
        let vals_reader: FastFieldReader<TFastValue> =
            FastFieldReader::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 `None`.
    pub fn u64(&self, field: Field) -> crate::Result<FastFieldReader<u64>> {
        self.check_type(field, FastType::U64, 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 `None`.
    pub fn i64(&self, field: Field) -> crate::Result<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 `None`.
    pub fn date(&self, field: Field) -> crate::Result<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 `None`.
    pub fn f64(&self, field: Field) -> crate::Result<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 `None`.
    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 `i64s` multi-valued fast field reader reader associated to `field`.
    ///
    /// If `field` is not a i64 multi-valued fast field, this method returns `None`.
    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 `None`.
    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 `None`.
    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 `None`.
    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 = FastFieldReader::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|>


<commit_before>use std::str::Chars;
use std::iter::Peekable;
use std::fmt::{Show,Formatter};
use std::fmt;

pub struct TokenValue<'a> {
  token: Token,
  value: &'a str
}

/// Lexer
pub struct Lexer<'a> {
  line: int,
  column: int,
  pos: int,
  iter: Peekable<char, Chars<'a>>,
  curr_ch: Option<char>,
  done: bool
}

/// Lexer tokens.
pub enum Token {
  PLUS,
  MINUS,
  INTEGER, // Any type of integer
  IDEN, // Identifier
  LPAREN,
  RPAREN,
  COLON
}

impl<'a> TokenValue<'a> {
  pub fn new(tok: Token, val: &'a str) -> TokenValue<'a> {
    TokenValue {
      token: tok,
      value: val
    }
  }
}

impl Eq for Token {
  fn eq(&self, other: &Token) -> bool {
    match *self {
      PLUS => match *other { PLUS => true, _ => false },
      MINUS => match *other { MINUS => true, _ => false },
      INTEGER => match *other { INTEGER => true, _ => false },
      IDEN => match *other { IDEN => true, _ => false },
      LPAREN => match *other { LPAREN => true, _ => false },
      RPAREN => match *other { RPAREN => true, _ => false },
      COLON => match *other { COLON => true, _ => false }
    }
  }
}

impl Show for Token {
  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
    let c = match *self {
      PLUS => &"+",
      MINUS => &"-",
      INTEGER => &"integer",
      IDEN => &"iden",
      LPAREN => &"(",
      RPAREN => &")",
      COLON => ":"
    };

    write!(f.buf, "({})", c)
  }
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    let it = input.chars().peekable();
    Lexer {
      line: 0,
      column: 0,
      pos: 0,
      iter: it,
      curr_ch: None,
      done: false
    }
  }

  pub fn bump(&mut self) {
    self.curr_ch = self.iter.next();
  }

  pub fn nextch_is(&mut self, ch: char) -> bool {
    self.bump();
    self.curr_ch.unwrap() == ch
  }

  pub fn peekch_is(&mut self, ch: char) -> bool {
    *self.iter.peek().unwrap() == ch
  }

  pub fn next_token(&mut self) -> Option<TokenValue<'a>> {

    for c in self.iter {
      match c {
        '(' => return Some(TokenValue::new(LPAREN, &"(")),
        ')' => return Some(TokenValue::new(RPAREN, &")")),
        '+' => return Some(TokenValue::new(PLUS, &"+")),
        '-' => return Some(TokenValue::new(MINUS, &"-")),
        ':' => return Some(TokenValue::new(COLON, &":")),
        '9' => return Some(TokenValue::new(INTEGER, &"9")),
        '8' => return Some(TokenValue::new(INTEGER, &"8")),
        '7' => return Some(TokenValue::new(INTEGER, &"7")),
        '6' => return Some(TokenValue::new(INTEGER, &"6")),
        '5' => return Some(TokenValue::new(INTEGER, &"5")),
        '4' => return Some(TokenValue::new(INTEGER, &"4")),
        '3' => return Some(TokenValue::new(INTEGER, &"3")),
        '2' => return Some(TokenValue::new(INTEGER, &"2")),
        '1' => return Some(TokenValue::new(INTEGER, &"1")),
        '0' => return Some(TokenValue::new(INTEGER, &"0")),
        _ => return None
      }
    }

    None
  }

}

#[cfg(test)]
mod test {
  use super::Lexer;
  use super::LPAREN;
  use super::TokenValue;

  #[test]
  fn bump() {
    let mut lex = Lexer::new(&"Hello World");
    lex.bump();
    assert_eq!(lex.curr_ch.unwrap(), 'H');
  }

  #[test]
  fn nextch() {
    let mut lex = Lexer::new(&"Woot");
    assert!(lex.nextch_is('W'));
  }

  #[test]
  fn peekable() {
    let mut lex = Lexer::new(&"Haha");
    lex.bump();
    assert!(lex.peekch_is('a'));
  }

  #[test]
  fn next_token() {
    // Should spit out two tokens (LPAREN,RPAREN)
    let mut lex = Lexer::new(&"()");
    assert!(lex.next_token().unwrap().value == &"(");
    assert!(lex.next_token().unwrap().value == &")");
  }

  #[test]
  fn return_complex_tokens() {
    let mut lex = Lexer::new(&"(+(():830");

    assert!(lex.next_token().unwrap().value == &"(");
    assert!(lex.next_token().unwrap().value == &"+");
    assert!(lex.next_token().unwrap().value == &"(");
    assert!(lex.next_token().unwrap().value == &"(");
    assert!(lex.next_token().unwrap().value == &")");
    assert!(lex.next_token().unwrap().value == &":");
    assert!(lex.next_token().unwrap().value == &"8");
    assert!(lex.next_token().unwrap().value == &"3");
    assert!(lex.next_token().unwrap().value == &"0");
  }

}<commit_msg>tests pass<commit_after>use std::str::Chars;
use std::fmt::{Show,Formatter};
use std::fmt;
use std::cast::transmute;

pub struct TokenValue<'a> {
  token: Token,
  value: &'a str
}

/// Lexer
pub struct Lexer<'a> {
  line: int,
  column: int,
  pos: int,
  iter: Chars<'a>,
  curr_ch: Option<char>,
  done: bool
}

/// Lexer tokens.
pub enum Token {
  PLUS,
  MINUS,
  INTEGER, // Any type of integer
  IDEN, // Identifier
  LPAREN,
  RPAREN,
  COLON
}

impl<'a> TokenValue<'a> {
  pub fn new(tok: Token, val: &'a str) -> TokenValue<'a> {
    TokenValue {
      token: tok,
      value: val
    }
  }
}

impl Eq for Token {
  fn eq(&self, other: &Token) -> bool {
    match *self {
      PLUS => match *other { PLUS => true, _ => false },
      MINUS => match *other { MINUS => true, _ => false },
      INTEGER => match *other { INTEGER => true, _ => false },
      IDEN => match *other { IDEN => true, _ => false },
      LPAREN => match *other { LPAREN => true, _ => false },
      RPAREN => match *other { RPAREN => true, _ => false },
      COLON => match *other { COLON => true, _ => false }
    }
  }
}

impl Show for Token {
  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
    let c = match *self {
      PLUS => &"+",
      MINUS => &"-",
      INTEGER => &"integer",
      IDEN => &"iden",
      LPAREN => &"(",
      RPAREN => &")",
      COLON => ":"
    };

    write!(f.buf, "({})", c)
  }
}

pub fn verify_iden_start(ch: char) -> bool {

  match ch {
    'A' => true,
    'a' => true,
    'B' => true,
    'b' => true,
    'C' => true,
    'c' => true,
    'D' => true,
    'd' => true,
    'E' => true,
    'e' => true,
    'F' => true,
    'f' => true,
    'G' => true,
    'g' => true,
    'H' => true,
    'h' => true,
    'I' => true,
    'i' => true,
    'J' => true,
    'j' => true,
    'K' => true,
    'k' => true,
    'L' => true,
    'l' => true,
    'M' => true,
    'm' => true,
    'N' => true,
    'n' => true,
    'O' => true,
    'o' => true,
    'P' => true,
    'p' => true,
    'Q' => true,
    'q' => true,
    'R' => true,
    'r' => true,
    'S' => true,
    's' => true,
    'T' => true,
    't' => true,
    'U' => true,
    'u' => true,
    'V' => true,
    'v' => true,
    'W' => true,
    'w' => true,
    'Y' => true,
    'y' => true,
    'Z' => true,
    'z' => true,
    '+' => true,
    '-' => true,
    '*' => true,
    _ => false
  }
}

// An iden is identified by:
// /^([A-Za-z-+*^][A-Za-z0-9-_]*)$/
pub fn is_iden<'b>(ch: &'b str) -> bool {
  // Create a new iterator
  let mut iter = ch.chars().peekable();

  // Verify the first character.
  if !verify_iden_start(iter.next().unwrap()) {
    return false;
  }

  for x in iter {
    match x {
      '\n' => return false,
      '\r' => return false,
      ' ' => return false,
      _  =>  if !verify_iden_start(x) { return false }
    }
  }

  true
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    let it = input.chars();
    Lexer {
      line: 0,
      column: 0,
      pos: 0,
      iter: it,
      curr_ch: None,
      done: false
    }
  }

  pub fn bump(&mut self) {
    self.curr_ch = self.iter.next();
  }

  pub fn nextch_is(&mut self, ch: char) -> bool {
    self.bump();
    self.curr_ch.unwrap() == ch
  }

  pub fn next_token(&mut self) -> Option<TokenValue<'a>> {

    for c in self.iter {
      match c {
        '(' => return Some(TokenValue::new(LPAREN, &"(")),
        ')' => return Some(TokenValue::new(RPAREN, &")")),
        '+' => return Some(TokenValue::new(PLUS, &"+")),
        '-' => return Some(TokenValue::new(MINUS, &"-")),
        ':' => return Some(TokenValue::new(COLON, &":")),
        '9' => return Some(TokenValue::new(INTEGER, &"9")),
        '8' => return Some(TokenValue::new(INTEGER, &"8")),
        '7' => return Some(TokenValue::new(INTEGER, &"7")),
        '6' => return Some(TokenValue::new(INTEGER, &"6")),
        '5' => return Some(TokenValue::new(INTEGER, &"5")),
        '4' => return Some(TokenValue::new(INTEGER, &"4")),
        '3' => return Some(TokenValue::new(INTEGER, &"3")),
        '2' => return Some(TokenValue::new(INTEGER, &"2")),
        '1' => return Some(TokenValue::new(INTEGER, &"1")),
        '0' => return Some(TokenValue::new(INTEGER, &"0")),
        _ => {
          println!("--");
          let mut it = self.iter;

          // Try and parse an identifier
          let mut iden = ~"";
          let mut prev = ~"";
          iden.push_char(c);

          for a in it {
            // FIXME(TheHydroImpulse): A huge fucking hack.
            if !is_iden(iden) && is_iden(prev) {
              return Some(TokenValue::new(IDEN, unsafe {
                transmute(prev.as_slice())
              }));
            }

            prev = iden.clone();
            iden.push_char(a);
            println!("iden = {}, is_iden(iden) = {}, prev = {}, ch = {}",
                iden, is_iden(iden), prev, a);
          }

          if !is_iden(iden) && is_iden(prev) {
            return Some(TokenValue::new(IDEN, unsafe {
              transmute(prev.as_slice())
            }));
          }
        }
      }
    }

    None
  }

}

#[cfg(test)]
mod test {
  use super::Lexer;
  use super::LPAREN;
  use super::TokenValue;

  #[test]
  fn bump() {
    let mut lex = Lexer::new(&"Hello World");
    lex.bump();
    assert_eq!(lex.curr_ch.unwrap(), 'H');
  }

  #[test]
  fn nextch() {
    let mut lex = Lexer::new(&"Woot");
    assert!(lex.nextch_is('W'));
  }

  #[test]
  fn next_token() {
    // Should spit out two tokens (LPAREN,RPAREN)
    let mut lex = Lexer::new(&"()");
    assert!(lex.next_token().unwrap().value == &"(");
    assert!(lex.next_token().unwrap().value == &")");
  }

  #[test]
  fn return_complex_tokens() {
    let mut lex = Lexer::new(&"(+(():830");

    assert!(lex.next_token().unwrap().value == &"(");
    assert!(lex.next_token().unwrap().value == &"+");
    assert!(lex.next_token().unwrap().value == &"(");
    assert!(lex.next_token().unwrap().value == &"(");
    assert!(lex.next_token().unwrap().value == &")");
    assert!(lex.next_token().unwrap().value == &":");
    assert!(lex.next_token().unwrap().value == &"8");
    assert!(lex.next_token().unwrap().value == &"3");
    assert!(lex.next_token().unwrap().value == &"0");
  }

  #[test]
  fn should_tokenize_identifier() {
    let mut lex = Lexer::new(&"(let)");
    println!("1");
    assert_eq!(lex.next_token().unwrap().value, &"(");
    assert_eq!(lex.next_token().unwrap().value, &"let");
  }

}<|endoftext|>


<commit_before>//! Data structures that represent module hierarchy and dependencies.
use arrayvec::ArrayString;
use petgraph::graphmap::DiGraphMap;
use std::cmp::{Ord, Ordering};
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::ops::Add;

/// Determines the maximum length of the #cfg that
/// can be attached to a mod definition.
const CONDITIONS_SIZE: usize = 100;

/// Determines the maximum length of a module's path.
///
/// eg: `"my_crate::foo::bar::baz"`.
const MOD_PATH_SIZE: usize = 200;

const SELF_KEYWORD: &str = "self";

pub const SEP: &str = "::";

pub type Graph = DiGraphMap<Module, Edge>;

/// Represents the scope of dependencies between modules.
///
/// See also [`Edge`].
#[derive(Clone, Debug, PartialEq)]
pub struct Dependency {
    /// Eg: `use path::to::mod::*;`
    refers_to_all: bool,
    /// Eg: `use path::to::mod;` or `use path::to::mod::{self, ...}`
    refers_to_mod: bool,
    /// Eg: `use path::to::mod::{some_function, SomeStruct};`
    referred_members: HashSet<String>,
}

impl Dependency {
    pub fn module() -> Self {
        Self {
            refers_to_all: false,
            refers_to_mod: true,
            referred_members: HashSet::new(),
        }
    }

    pub fn all() -> Self {
        Self {
            refers_to_all: true,
            refers_to_mod: false,
            referred_members: HashSet::new(),
        }
    }

    pub fn members(mut members: Vec<String>) -> Self {
        let refers_to_mod: bool = members.contains(&String::from(SELF_KEYWORD));
        let referred_members: HashSet<String> =
            members.drain(..).filter(|m| m != SELF_KEYWORD).collect();
        Self {
            refers_to_all: false,
            refers_to_mod,
            referred_members,
        }
    }
}

impl Add for Dependency {
    type Output = Dependency;

    fn add(self, other: Dependency) -> Dependency {
        Dependency {
            refers_to_all: self.refers_to_all || other.refers_to_all,
            refers_to_mod: self.refers_to_mod || other.refers_to_mod,
            referred_members: self
                .referred_members
                .union(&other.referred_members)
                .cloned()
                .collect(),
        }
    }
}

/// Represents an association between modules.
///
/// This enum is intended to be used with directed graphs because
/// relationships represented are asymmetric.
#[derive(Clone, Debug, PartialEq)]
pub enum Edge {
    /// Represents a **parent ⇒ child** relationship.
    Child,
    /// Represents a **dependent ⇒ dependency** relationship created by `use`.
    Dependency(Dependency),
    /// Like `Child` but the **child** module is an orphan.  So this
    /// represents a _lack of_ semantic relationship.
    Unconnected,
}

/// Builds a graph, `DiGraphMap<Mod, Edge>` to be specific using domain
/// specific operations.
pub struct GraphBuilder {
    graph: Graph,
    uses: HashMap<String, HashSet<String>>,
}

impl GraphBuilder {
    pub fn new() -> Self {
        Self {
            graph: DiGraphMap::new(),
            uses: HashMap::new(),
        }
    }

    /// Define a public module that has no parent.
    ///
    /// # Panics
    /// If `name` contains `"::"`.
    pub fn add_crate_root(&mut self, name: &str) {
        assert!(!name.contains(SEP));
        self.graph.add_node(Module::new_root(name));
    }

    /// Define a sub-modules and associate it with its parent.
    ///
    /// # Panics
    /// - If the parent is not already defined.
    /// - If parent-child relationship for this pair is already defined.
    pub fn add_mod(
        &mut self,
        path: &str,
        name: &str,
        visibility: Visibility,
        conditions: Option<&str>,
    ) {
        let parent: Module = self.find(path).unwrap();
        let node = Module::new(&[path, SEP, name].concat(), Some(visibility), conditions);
        self.graph.add_node(node);
        assert!(self.graph.add_edge(parent, node, Edge::Child).is_none());
    }

    pub fn add_orphan(&mut self, path: &str, name: &str) {
        let parent: Module = self.find(path).unwrap();
        let node = Module::new(&[path, SEP, name].concat(), None, None);
        self.graph.add_node(node);
        assert!(self
            .graph
            .add_edge(parent, node, Edge::Unconnected)
            .is_none());
    }

    pub fn add_use(&mut self, path: &str, use_: &str) {
        if !self.uses.contains_key(path) {
            self.uses.insert(path.to_owned(), HashSet::new());
        }
        self.uses.get_mut(path).unwrap().insert(use_.to_owned());
    }

    /// Build the graph, consuming this builder, or return an error.
    pub fn build(mut self) -> Result<Graph, GraphError> {
        // Take ownership of uses separately so that we can still
        // call the builder struct as mutable.
        let uses: HashMap<String, HashSet<String>> =
            std::mem::replace(&mut self.uses, HashMap::new());
        let mut result: Result<(), GraphError> = Ok(());
        for (from, uses) in uses {
            let from_module = self
                .find(&from)
                .expect("Trying to add dependency from an unknown module");
            for to in uses {
                result = self.add_dependency(from_module, &to);
                if result.is_err() {
                    break;
                }
            }
        }
        result.map(|_| self.graph)
    }

    pub fn find(&self, path: &str) -> Option<Module> {
        self.graph.nodes().find(|m| m.path() == path)
    }

    fn add_dependency(&mut self, from: Module, use_: &str) -> Result<(), GraphError> {
        match self.find(use_) {
            Some(to) => {
                // TODO: Don't bash on existing dependency.
                assert!(self
                    .graph
                    .add_edge(from, to, Edge::Dependency(Dependency::module()))
                    .is_none());
                Ok(())
            }
            None => Err(GraphError::UnknownModule(use_.to_owned())),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum GraphError {
    UnknownModule(String),
}

/// Represents a node that is a module in the graph.
#[derive(Clone, Copy, Debug)]
pub struct Module {
    is_root: bool,
    /// Because this struct needs to be `Copy`, using `String` or `&str` was
    /// out of the question.  `ArrayString` provides a sized and owned string
    /// that is backed by a byte array.
    ///
    /// See also [MOD_PATH_SIZE]
    path: ArrayString<[u8; MOD_PATH_SIZE]>,
    name_ridx: usize,
    visibility: Option<Visibility>,
    /// This needs to be `Copy` for the same reason as `path`.
    conditions: Option<ArrayString<[u8; CONDITIONS_SIZE]>>,
}

impl Module {
    pub fn new(path: &str, visibility: Option<Visibility>, conditions: Option<&str>) -> Self {
        Self {
            is_root: false,
            path: ArrayString::<[u8; MOD_PATH_SIZE]>::from(path)
                .unwrap_or_else(|_| panic!("Module path is too long")),
            name_ridx: path.rfind(SEP).map(|i| i + SEP.len()).unwrap_or(0),
            visibility,
            conditions: conditions.map(|c| {
                ArrayString::<[u8; CONDITIONS_SIZE]>::from(c)
                    .unwrap_or_else(|_| panic!("Conditions are too long"))
            }),
        }
    }

    pub fn new_root(path: &str) -> Self {
        let mut m = Self::new(path, Some(Visibility::Public), None);
        m.is_root = true;
        m
    }

    pub fn conditions(&self) -> Option<&str> {
        self.conditions.as_ref().map(|c| &c[..])
    }

    pub fn name(&self) -> &str {
        &self.path[self.name_ridx..]
    }

    pub fn is_orphan(&self) -> bool {
        self.visibility.is_none()
    }

    pub fn is_root(&self) -> bool {
        self.is_root
    }

    pub fn path(&self) -> &str {
        &self.path.as_str()
    }

    pub fn visibility(&self) -> Option<Visibility> {
        self.visibility
    }
}

impl Eq for Module {}

impl Hash for Module {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path().hash(state);
    }
}

impl Ord for Module {
    fn cmp(&self, other: &Self) -> Ordering {
        self.path().cmp(&other.path())
    }
}

impl PartialEq for Module {
    fn eq(&self, other: &Self) -> bool {
        self.path() == other.path()
    }
}

impl PartialOrd for Module {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

// TODO: We should support more kinds of visibility.
//
// Defined kinds are:
//
// - Public
// - Crate
// - Restricted
// - Inherited
//
// See: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/enum.VisibilityKind.html
#[derive(Clone, Copy, Debug)]
pub enum Visibility {
    Public,
    Private,
}

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

    #[test]
    fn new_builder_produces_an_empty_directed_graph() {
        let builder = GraphBuilder::new();
        let graph: Graph = builder.build().unwrap();
        assert_eq!(0, graph.node_count());
        assert_eq!(0, graph.edge_count());
    }

    #[test]
    fn add_crate_root_adds_a_node() {
        let mut builder = GraphBuilder::new();
        builder.add_crate_root("crate-root");
        let graph: Graph = builder.build().unwrap();
        assert_eq!(1, graph.node_count());
        assert_eq!(0, graph.edge_count());
        assert!(graph.contains_node(Module::new("crate-root", Some(Visibility::Public), None)));
    }

    #[test]
    fn add_mod_creates_an_association_with_parent() {
        let foo: Module = Module::new("foo", Some(Visibility::Public), None);
        let bar: Module = Module::new("foo::bar", Some(Visibility::Public), None);
        let baz: Module = Module::new("foo::bar::baz", Some(Visibility::Private), None);
        let mut builder = GraphBuilder::new();
        builder.add_crate_root("foo");
        builder.add_mod("foo", "bar", Visibility::Public, None);
        builder.add_mod("foo::bar", "baz", Visibility::Private, None);
        let graph: Graph = builder.build().unwrap();
        assert_eq!(3, graph.node_count());
        assert_eq!(2, graph.edge_count());
        assert!(graph.contains_node(foo));
        assert!(graph.contains_node(bar));
        assert!(graph.contains_node(baz));
        assert_eq!(
            vec![(foo, bar, &Edge::Child), (bar, baz, &Edge::Child)],
            graph.all_edges().collect::<Vec<(Module, Module, &Edge)>>()
        );
    }

    #[test]
    #[should_panic(expected = "Module path is too long")]
    fn add_mod_panics_if_path_is_longer_than_limit() {
        let name = "foo";
        let path = std::str::from_utf8([114; MOD_PATH_SIZE - 4].as_ref()).unwrap(); // 'r'
        let concatenated = format!("{}::{}", path, name);
        assert!(concatenated.len() > MOD_PATH_SIZE);
        let mut builder = GraphBuilder::new();
        builder.add_crate_root(path);
        builder.add_mod(path, name, Visibility::Public, None);
    }

    #[test]
    fn adding_a_use_is_idempotent() {
        let mut builder = GraphBuilder::new();
        builder.add_crate_root("foo");
        builder.add_mod("foo", "bar", Visibility::Public, None);
        builder.add_mod("foo", "baz", Visibility::Private, None);
        builder.add_use("foo::bar", "foo::baz");
        builder.add_use("foo::bar", "foo::baz");
        let graph = builder.build().unwrap();
        assert_eq!(3, graph.edge_count());
    }

    #[test]
    fn add_dep_requires_both_modules_to_be_defined() {
        {
            let mut builder = GraphBuilder::new();
            builder.add_crate_root("foo");
            builder.add_mod("foo", "bar", Visibility::Public, None);
            builder.add_use("foo::bar", "foo::baz");
            assert_eq!(
                Some(GraphError::UnknownModule(String::from("foo::baz"))),
                builder.build().err()
            );
        }
        {
            let mut builder = GraphBuilder::new();
            builder.add_crate_root("foo");
            builder.add_mod("foo", "bar", Visibility::Private, None);
            builder.add_use("foo::bar", "foo::baz");
            builder.add_use("foo::bar", "foo::fubar");
            builder.add_mod("foo", "baz", Visibility::Private, None);
            assert_eq!(
                Some(GraphError::UnknownModule(String::from("foo::fubar"))),
                builder.build().err()
            );
        }
    }

    #[test]
    #[should_panic(expected = "Trying to add dependency from an unknown module")]
    #[allow(unused_must_use)]
    fn dependency_from_unknown_module_panics() {
        {
            let mut builder = GraphBuilder::new();
            builder.add_crate_root("foo");
            builder.add_use("foo::bar", "foo::baz");
            builder.build();
        }
    }

    #[test]
    fn orphaned_modules_are_linked_to_their_parent_via_unconnected_edges() {
        let mut builder = GraphBuilder::new();
        builder.add_crate_root("foo");
        builder.add_mod("foo", "bar", Visibility::Public, None);
        builder.add_orphan("foo", "baz");
        builder.add_orphan("foo::bar", "bat");
        let graph = builder.build().unwrap();
        assert_eq!(3, graph.edge_count());

        // Check edge `foo -> baz`
        assert!(graph.contains_edge(
            Module::new_root("foo"),
            Module::new("foo::bar", Some(Visibility::Public), None)
        ));
        assert_eq!(
            Some(&Edge::Unconnected),
            graph.edge_weight(
                Module::new_root("foo"),
                Module::new("foo::baz", Some(Visibility::Public), None)
            )
        );

        // Check edge `bar -> bat`
        assert!(graph.contains_edge(
            Module::new("foo::bar", Some(Visibility::Public), None),
            Module::new("foo::bar::bat", Some(Visibility::Public), None)
        ));
        assert_eq!(
            Some(&Edge::Unconnected),
            graph.edge_weight(
                Module::new("foo::bar", Some(Visibility::Public), None),
                Module::new("foo::bar::bat", Some(Visibility::Public), None)
            )
        );
    }

    #[test]
    fn module_name() {
        assert_eq!(Module::new_root("foo").name(), "foo");
        assert_eq!(
            Module::new("foo::bar", Some(Visibility::Public), None).name(),
            "bar"
        );
        assert_eq!(
            Module::new("foo::bar::baz::bat::quux", Some(Visibility::Private), None).name(),
            "quux"
        );
    }
}
<commit_msg>Refactor dependecy resoulution loops in FP style<commit_after>//! Data structures that represent module hierarchy and dependencies.
use arrayvec::ArrayString;
use petgraph::graphmap::DiGraphMap;
use std::cmp::{Ord, Ordering};
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::ops::Add;

/// Determines the maximum length of the #cfg that
/// can be attached to a mod definition.
const CONDITIONS_SIZE: usize = 100;

/// Determines the maximum length of a module's path.
///
/// eg: `"my_crate::foo::bar::baz"`.
const MOD_PATH_SIZE: usize = 200;

const SELF_KEYWORD: &str = "self";

pub const SEP: &str = "::";

pub type Graph = DiGraphMap<Module, Edge>;

/// Represents the scope of dependencies between modules.
///
/// See also [`Edge`].
#[derive(Clone, Debug, PartialEq)]
pub struct Dependency {
    /// Eg: `use path::to::mod::*;`
    refers_to_all: bool,
    /// Eg: `use path::to::mod;` or `use path::to::mod::{self, ...}`
    refers_to_mod: bool,
    /// Eg: `use path::to::mod::{some_function, SomeStruct};`
    referred_members: HashSet<String>,
}

impl Dependency {
    pub fn module() -> Self {
        Self {
            refers_to_all: false,
            refers_to_mod: true,
            referred_members: HashSet::new(),
        }
    }

    pub fn all() -> Self {
        Self {
            refers_to_all: true,
            refers_to_mod: false,
            referred_members: HashSet::new(),
        }
    }

    pub fn members(mut members: Vec<String>) -> Self {
        let refers_to_mod: bool = members.contains(&String::from(SELF_KEYWORD));
        let referred_members: HashSet<String> =
            members.drain(..).filter(|m| m != SELF_KEYWORD).collect();
        Self {
            refers_to_all: false,
            refers_to_mod,
            referred_members,
        }
    }
}

impl Add for Dependency {
    type Output = Dependency;

    fn add(self, other: Dependency) -> Dependency {
        Dependency {
            refers_to_all: self.refers_to_all || other.refers_to_all,
            refers_to_mod: self.refers_to_mod || other.refers_to_mod,
            referred_members: self
                .referred_members
                .union(&other.referred_members)
                .cloned()
                .collect(),
        }
    }
}

/// Represents an association between modules.
///
/// This enum is intended to be used with directed graphs because
/// relationships represented are asymmetric.
#[derive(Clone, Debug, PartialEq)]
pub enum Edge {
    /// Represents a **parent ⇒ child** relationship.
    Child,
    /// Represents a **dependent ⇒ dependency** relationship created by `use`.
    Dependency(Dependency),
    /// Like `Child` but the **child** module is an orphan.  So this
    /// represents a _lack of_ semantic relationship.
    Unconnected,
}

/// Builds a graph, `DiGraphMap<Mod, Edge>` to be specific using domain
/// specific operations.
pub struct GraphBuilder {
    graph: Graph,
    uses: HashMap<String, HashSet<String>>,
}

impl GraphBuilder {
    pub fn new() -> Self {
        Self {
            graph: DiGraphMap::new(),
            uses: HashMap::new(),
        }
    }

    /// Define a public module that has no parent.
    ///
    /// # Panics
    /// If `name` contains `"::"`.
    pub fn add_crate_root(&mut self, name: &str) {
        assert!(!name.contains(SEP));
        self.graph.add_node(Module::new_root(name));
    }

    /// Define a sub-modules and associate it with its parent.
    ///
    /// # Panics
    /// - If the parent is not already defined.
    /// - If parent-child relationship for this pair is already defined.
    pub fn add_mod(
        &mut self,
        path: &str,
        name: &str,
        visibility: Visibility,
        conditions: Option<&str>,
    ) {
        let parent: Module = self.find(path).unwrap();
        let node = Module::new(&[path, SEP, name].concat(), Some(visibility), conditions);
        self.graph.add_node(node);
        assert!(self.graph.add_edge(parent, node, Edge::Child).is_none());
    }

    pub fn add_orphan(&mut self, path: &str, name: &str) {
        let parent: Module = self.find(path).unwrap();
        let node = Module::new(&[path, SEP, name].concat(), None, None);
        self.graph.add_node(node);
        assert!(self
            .graph
            .add_edge(parent, node, Edge::Unconnected)
            .is_none());
    }

    pub fn add_use(&mut self, path: &str, use_: &str) {
        if !self.uses.contains_key(path) {
            self.uses.insert(path.to_owned(), HashSet::new());
        }
        self.uses.get_mut(path).unwrap().insert(use_.to_owned());
    }

    /// Build the graph, consuming this builder, or return an error.
    pub fn build(mut self) -> Result<Graph, GraphError> {
        // Take ownership of uses separately so that we can still
        // call the builder struct as mutable.
        let uses: HashMap<String, HashSet<String>> =
            std::mem::replace(&mut self.uses, HashMap::new());

        uses.iter()
            .fold(Ok(()), |result, (from, uses)| {
                // Go through each module (from) that has uses recorded
                // but break as soon as a step results in an error.
                result.and_then(|_| {
                    // We can safely unwrap here since we expect the module
                    // to be visited before any use can be recorded.
                    let from_module = self
                        .find(&from)
                        .expect("Trying to add dependency from an unknown module");
                    // Go through uses for from_module, break
                    // as soon as a error is encountered.
                    uses.iter().fold(Ok(()), |result, to| {
                        result.and_then(|_| self.add_dependency(from_module, &to))
                    })
                })
            })
            // If all went right, return Ok(self.graph)
            .map(|_| self.graph)
    }

    pub fn find(&self, path: &str) -> Option<Module> {
        self.graph.nodes().find(|m| m.path() == path)
    }

    fn add_dependency(&mut self, from: Module, use_: &str) -> Result<(), GraphError> {
        match self.find(use_) {
            Some(to) => {
                // TODO: Don't bash on existing dependency.
                assert!(self
                    .graph
                    .add_edge(from, to, Edge::Dependency(Dependency::module()))
                    .is_none());
                Ok(())
            }
            None => Err(GraphError::UnknownModule(use_.to_owned())),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum GraphError {
    UnknownModule(String),
}

/// Represents a node that is a module in the graph.
#[derive(Clone, Copy, Debug)]
pub struct Module {
    is_root: bool,
    /// Because this struct needs to be `Copy`, using `String` or `&str` was
    /// out of the question.  `ArrayString` provides a sized and owned string
    /// that is backed by a byte array.
    ///
    /// See also [MOD_PATH_SIZE]
    path: ArrayString<[u8; MOD_PATH_SIZE]>,
    name_ridx: usize,
    visibility: Option<Visibility>,
    /// This needs to be `Copy` for the same reason as `path`.
    conditions: Option<ArrayString<[u8; CONDITIONS_SIZE]>>,
}

impl Module {
    pub fn new(path: &str, visibility: Option<Visibility>, conditions: Option<&str>) -> Self {
        Self {
            is_root: false,
            path: ArrayString::<[u8; MOD_PATH_SIZE]>::from(path)
                .unwrap_or_else(|_| panic!("Module path is too long")),
            name_ridx: path.rfind(SEP).map(|i| i + SEP.len()).unwrap_or(0),
            visibility,
            conditions: conditions.map(|c| {
                ArrayString::<[u8; CONDITIONS_SIZE]>::from(c)
                    .unwrap_or_else(|_| panic!("Conditions are too long"))
            }),
        }
    }

    pub fn new_root(path: &str) -> Self {
        let mut m = Self::new(path, Some(Visibility::Public), None);
        m.is_root = true;
        m
    }

    pub fn conditions(&self) -> Option<&str> {
        self.conditions.as_ref().map(|c| &c[..])
    }

    pub fn name(&self) -> &str {
        &self.path[self.name_ridx..]
    }

    pub fn is_orphan(&self) -> bool {
        self.visibility.is_none()
    }

    pub fn is_root(&self) -> bool {
        self.is_root
    }

    pub fn path(&self) -> &str {
        &self.path.as_str()
    }

    pub fn visibility(&self) -> Option<Visibility> {
        self.visibility
    }
}

impl Eq for Module {}

impl Hash for Module {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path().hash(state);
    }
}

impl Ord for Module {
    fn cmp(&self, other: &Self) -> Ordering {
        self.path().cmp(&other.path())
    }
}

impl PartialEq for Module {
    fn eq(&self, other: &Self) -> bool {
        self.path() == other.path()
    }
}

impl PartialOrd for Module {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

// TODO: We should support more kinds of visibility.
//
// Defined kinds are:
//
// - Public
// - Crate
// - Restricted
// - Inherited
//
// See: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/enum.VisibilityKind.html
#[derive(Clone, Copy, Debug)]
pub enum Visibility {
    Public,
    Private,
}

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

    #[test]
    fn new_builder_produces_an_empty_directed_graph() {
        let builder = GraphBuilder::new();
        let graph: Graph = builder.build().unwrap();
        assert_eq!(0, graph.node_count());
        assert_eq!(0, graph.edge_count());
    }

    #[test]
    fn add_crate_root_adds_a_node() {
        let mut builder = GraphBuilder::new();
        builder.add_crate_root("crate-root");
        let graph: Graph = builder.build().unwrap();
        assert_eq!(1, graph.node_count());
        assert_eq!(0, graph.edge_count());
        assert!(graph.contains_node(Module::new("crate-root", Some(Visibility::Public), None)));
    }

    #[test]
    fn add_mod_creates_an_association_with_parent() {
        let foo: Module = Module::new("foo", Some(Visibility::Public), None);
        let bar: Module = Module::new("foo::bar", Some(Visibility::Public), None);
        let baz: Module = Module::new("foo::bar::baz", Some(Visibility::Private), None);
        let mut builder = GraphBuilder::new();
        builder.add_crate_root("foo");
        builder.add_mod("foo", "bar", Visibility::Public, None);
        builder.add_mod("foo::bar", "baz", Visibility::Private, None);
        let graph: Graph = builder.build().unwrap();
        assert_eq!(3, graph.node_count());
        assert_eq!(2, graph.edge_count());
        assert!(graph.contains_node(foo));
        assert!(graph.contains_node(bar));
        assert!(graph.contains_node(baz));
        assert_eq!(
            vec![(foo, bar, &Edge::Child), (bar, baz, &Edge::Child)],
            graph.all_edges().collect::<Vec<(Module, Module, &Edge)>>()
        );
    }

    #[test]
    #[should_panic(expected = "Module path is too long")]
    fn add_mod_panics_if_path_is_longer_than_limit() {
        let name = "foo";
        let path = std::str::from_utf8([114; MOD_PATH_SIZE - 4].as_ref()).unwrap(); // 'r'
        let concatenated = format!("{}::{}", path, name);
        assert!(concatenated.len() > MOD_PATH_SIZE);
        let mut builder = GraphBuilder::new();
        builder.add_crate_root(path);
        builder.add_mod(path, name, Visibility::Public, None);
    }

    #[test]
    fn adding_a_use_is_idempotent() {
        let mut builder = GraphBuilder::new();
        builder.add_crate_root("foo");
        builder.add_mod("foo", "bar", Visibility::Public, None);
        builder.add_mod("foo", "baz", Visibility::Private, None);
        builder.add_use("foo::bar", "foo::baz");
        builder.add_use("foo::bar", "foo::baz");
        let graph = builder.build().unwrap();
        assert_eq!(3, graph.edge_count());
    }

    #[test]
    fn add_dep_requires_both_modules_to_be_defined() {
        {
            let mut builder = GraphBuilder::new();
            builder.add_crate_root("foo");
            builder.add_mod("foo", "bar", Visibility::Public, None);
            builder.add_use("foo::bar", "foo::baz");
            assert_eq!(
                Some(GraphError::UnknownModule(String::from("foo::baz"))),
                builder.build().err()
            );
        }
        {
            let mut builder = GraphBuilder::new();
            builder.add_crate_root("foo");
            builder.add_mod("foo", "bar", Visibility::Private, None);
            builder.add_use("foo::bar", "foo::baz");
            builder.add_use("foo::bar", "foo::fubar");
            builder.add_mod("foo", "baz", Visibility::Private, None);
            assert_eq!(
                Some(GraphError::UnknownModule(String::from("foo::fubar"))),
                builder.build().err()
            );
        }
    }

    #[test]
    #[should_panic(expected = "Trying to add dependency from an unknown module")]
    #[allow(unused_must_use)]
    fn dependency_from_unknown_module_panics() {
        {
            let mut builder = GraphBuilder::new();
            builder.add_crate_root("foo");
            builder.add_use("foo::bar", "foo::baz");
            builder.build();
        }
    }

    #[test]
    fn orphaned_modules_are_linked_to_their_parent_via_unconnected_edges() {
        let mut builder = GraphBuilder::new();
        builder.add_crate_root("foo");
        builder.add_mod("foo", "bar", Visibility::Public, None);
        builder.add_orphan("foo", "baz");
        builder.add_orphan("foo::bar", "bat");
        let graph = builder.build().unwrap();
        assert_eq!(3, graph.edge_count());

        // Check edge `foo -> baz`
        assert!(graph.contains_edge(
            Module::new_root("foo"),
            Module::new("foo::bar", Some(Visibility::Public), None)
        ));
        assert_eq!(
            Some(&Edge::Unconnected),
            graph.edge_weight(
                Module::new_root("foo"),
                Module::new("foo::baz", Some(Visibility::Public), None)
            )
        );

        // Check edge `bar -> bat`
        assert!(graph.contains_edge(
            Module::new("foo::bar", Some(Visibility::Public), None),
            Module::new("foo::bar::bat", Some(Visibility::Public), None)
        ));
        assert_eq!(
            Some(&Edge::Unconnected),
            graph.edge_weight(
                Module::new("foo::bar", Some(Visibility::Public), None),
                Module::new("foo::bar::bat", Some(Visibility::Public), None)
            )
        );
    }

    #[test]
    fn module_name() {
        assert_eq!(Module::new_root("foo").name(), "foo");
        assert_eq!(
            Module::new("foo::bar", Some(Visibility::Public), None).name(),
            "bar"
        );
        assert_eq!(
            Module::new("foo::bar::baz::bat::quux", Some(Visibility::Private), None).name(),
            "quux"
        );
    }
}
<|endoftext|>