<commit_before>use crate::client::{InnerClient, Responses};
use crate::codec::FrontendMessage;
use crate::connection::RequestMessages;
use crate::types::{BorrowToSql, IsNull};
use crate::{Error, Portal, Row, Statement};
use bytes::{Bytes, BytesMut};
use futures::{ready, Stream};
use log::{debug, log_enabled, Level};
use pin_project_lite::pin_project;
use postgres_protocol::message::backend::Message;
use postgres_protocol::message::frontend;
use std::fmt;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::task::{Context, Poll};

struct BorrowToSqlParamsDebug<'a, T>(&'a [T]);

impl<'a, T> fmt::Debug for BorrowToSqlParamsDebug<'a, T>
where
    T: BorrowToSql,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_list()
            .entries(self.0.iter().map(|x| x.borrow_to_sql()))
            .finish()
    }
}

pub async fn query<P, I>(
    client: &InnerClient,
    statement: Statement,
    params: I,
) -> Result<RowStream, Error>
where
    P: BorrowToSql,
    I: IntoIterator<Item = P>,
    I::IntoIter: ExactSizeIterator,
{
    let buf = if log_enabled!(Level::Debug) {
        let params = params.into_iter().collect::<Vec<_>>();
        debug!(
            "executing statement {} with parameters: {:?}",
            statement.name(),
            BorrowToSqlParamsDebug(params.as_slice()),
        );
        encode(client, &statement, params)?
    } else {
        encode(client, &statement, params)?
    };
    let responses = start(client, buf).await?;
    Ok(RowStream {
        statement,
        responses,
        _p: PhantomPinned,
    })
}

pub async fn query_portal(
    client: &InnerClient,
    portal: &Portal,
    max_rows: i32,
) -> Result<RowStream, Error> {
    let buf = client.with_buf(|buf| {
        frontend::execute(portal.name(), max_rows, buf).map_err(Error::encode)?;
        frontend::sync(buf);
        Ok(buf.split().freeze())
    })?;

    let responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?;

    Ok(RowStream {
        statement: portal.statement().clone(),
        responses,
        _p: PhantomPinned,
    })
}

pub async fn execute<P, I>(
    client: &InnerClient,
    statement: Statement,
    params: I,
) -> Result<u64, Error>
where
    P: BorrowToSql,
    I: IntoIterator<Item = P>,
    I::IntoIter: ExactSizeIterator,
{
    let buf = if log_enabled!(Level::Debug) {
        let params = params.into_iter().collect::<Vec<_>>();
        debug!(
            "executing statement {} with parameters: {:?}",
            statement.name(),
            BorrowToSqlParamsDebug(params.as_slice()),
        );
        encode(client, &statement, params)?
    } else {
        encode(client, &statement, params)?
    };
    let mut responses = start(client, buf).await?;

    let mut rows = 0;
    loop {
        match responses.next().await? {
            Message::DataRow(_) => {}
            Message::CommandComplete(body) => {
                rows = body
                    .tag()
                    .map_err(Error::parse)?
                    .rsplit(' ')
                    .next()
                    .unwrap()
                    .parse()
                    .unwrap_or(0);
            }
            Message::EmptyQueryResponse => rows = 0,
            Message::ReadyForQuery(_) => return Ok(rows),
            _ => return Err(Error::unexpected_message()),
        }
    }
}

async fn start(client: &InnerClient, buf: Bytes) -> Result<Responses, Error> {
    let mut responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?;

    match responses.next().await? {
        Message::BindComplete => {}
        _ => return Err(Error::unexpected_message()),
    }

    Ok(responses)
}

pub fn encode<P, I>(client: &InnerClient, statement: &Statement, params: I) -> Result<Bytes, Error>
where
    P: BorrowToSql,
    I: IntoIterator<Item = P>,
    I::IntoIter: ExactSizeIterator,
{
    client.with_buf(|buf| {
        encode_bind(statement, params, "", buf)?;
        frontend::execute("", 0, buf).map_err(Error::encode)?;
        frontend::sync(buf);
        Ok(buf.split().freeze())
    })
}

pub fn encode_bind<P, I>(
    statement: &Statement,
    params: I,
    portal: &str,
    buf: &mut BytesMut,
) -> Result<(), Error>
where
    P: BorrowToSql,
    I: IntoIterator<Item = P>,
    I::IntoIter: ExactSizeIterator,
{
    let (param_formats, params): (Vec<_>, Vec<_>) = params
        .into_iter()
        .map(|p| { (p.borrow_to_sql().encode_format() as i16, p) })
        .unzip();
    let params = params.into_iter();

    assert!(
        statement.params().len() == params.len(),
        "expected {} parameters but got {}",
        statement.params().len(),
        params.len()
    );

    let mut error_idx = 0;
    let r = frontend::bind(
        portal,
        statement.name(),
        param_formats,
        params.zip(statement.params()).enumerate(),
        |(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(ty, buf) {
            Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
            Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
            Err(e) => {
                error_idx = idx;
                Err(e)
            }
        },
        Some(1),
        buf,
    );
    match r {
        Ok(()) => Ok(()),
        Err(frontend::BindError::Conversion(e)) => Err(Error::to_sql(e, error_idx)),
        Err(frontend::BindError::Serialization(e)) => Err(Error::encode(e)),
    }
}

pin_project! {
    /// A stream of table rows.
    pub struct RowStream {
        statement: Statement,
        responses: Responses,
        #[pin]
        _p: PhantomPinned,
    }
}

impl Stream for RowStream {
    type Item = Result<Row, Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let this = self.project();
        loop {
            match ready!(this.responses.poll_next(cx)?) {
                Message::DataRow(body) => {
                    return Poll::Ready(Some(Ok(Row::new(this.statement.clone(), body)?)))
                }
                Message::EmptyQueryResponse
                | Message::CommandComplete(_)
                | Message::PortalSuspended => {}
                Message::ReadyForQuery(_) => return Poll::Ready(None),
                _ => return Poll::Ready(Some(Err(Error::unexpected_message()))),
            }
        }
    }
}
<commit_msg>rustfmt<commit_after>use crate::client::{InnerClient, Responses};
use crate::codec::FrontendMessage;
use crate::connection::RequestMessages;
use crate::types::{BorrowToSql, IsNull};
use crate::{Error, Portal, Row, Statement};
use bytes::{Bytes, BytesMut};
use futures::{ready, Stream};
use log::{debug, log_enabled, Level};
use pin_project_lite::pin_project;
use postgres_protocol::message::backend::Message;
use postgres_protocol::message::frontend;
use std::fmt;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::task::{Context, Poll};

struct BorrowToSqlParamsDebug<'a, T>(&'a [T]);

impl<'a, T> fmt::Debug for BorrowToSqlParamsDebug<'a, T>
where
    T: BorrowToSql,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_list()
            .entries(self.0.iter().map(|x| x.borrow_to_sql()))
            .finish()
    }
}

pub async fn query<P, I>(
    client: &InnerClient,
    statement: Statement,
    params: I,
) -> Result<RowStream, Error>
where
    P: BorrowToSql,
    I: IntoIterator<Item = P>,
    I::IntoIter: ExactSizeIterator,
{
    let buf = if log_enabled!(Level::Debug) {
        let params = params.into_iter().collect::<Vec<_>>();
        debug!(
            "executing statement {} with parameters: {:?}",
            statement.name(),
            BorrowToSqlParamsDebug(params.as_slice()),
        );
        encode(client, &statement, params)?
    } else {
        encode(client, &statement, params)?
    };
    let responses = start(client, buf).await?;
    Ok(RowStream {
        statement,
        responses,
        _p: PhantomPinned,
    })
}

pub async fn query_portal(
    client: &InnerClient,
    portal: &Portal,
    max_rows: i32,
) -> Result<RowStream, Error> {
    let buf = client.with_buf(|buf| {
        frontend::execute(portal.name(), max_rows, buf).map_err(Error::encode)?;
        frontend::sync(buf);
        Ok(buf.split().freeze())
    })?;

    let responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?;

    Ok(RowStream {
        statement: portal.statement().clone(),
        responses,
        _p: PhantomPinned,
    })
}

pub async fn execute<P, I>(
    client: &InnerClient,
    statement: Statement,
    params: I,
) -> Result<u64, Error>
where
    P: BorrowToSql,
    I: IntoIterator<Item = P>,
    I::IntoIter: ExactSizeIterator,
{
    let buf = if log_enabled!(Level::Debug) {
        let params = params.into_iter().collect::<Vec<_>>();
        debug!(
            "executing statement {} with parameters: {:?}",
            statement.name(),
            BorrowToSqlParamsDebug(params.as_slice()),
        );
        encode(client, &statement, params)?
    } else {
        encode(client, &statement, params)?
    };
    let mut responses = start(client, buf).await?;

    let mut rows = 0;
    loop {
        match responses.next().await? {
            Message::DataRow(_) => {}
            Message::CommandComplete(body) => {
                rows = body
                    .tag()
                    .map_err(Error::parse)?
                    .rsplit(' ')
                    .next()
                    .unwrap()
                    .parse()
                    .unwrap_or(0);
            }
            Message::EmptyQueryResponse => rows = 0,
            Message::ReadyForQuery(_) => return Ok(rows),
            _ => return Err(Error::unexpected_message()),
        }
    }
}

async fn start(client: &InnerClient, buf: Bytes) -> Result<Responses, Error> {
    let mut responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?;

    match responses.next().await? {
        Message::BindComplete => {}
        _ => return Err(Error::unexpected_message()),
    }

    Ok(responses)
}

pub fn encode<P, I>(client: &InnerClient, statement: &Statement, params: I) -> Result<Bytes, Error>
where
    P: BorrowToSql,
    I: IntoIterator<Item = P>,
    I::IntoIter: ExactSizeIterator,
{
    client.with_buf(|buf| {
        encode_bind(statement, params, "", buf)?;
        frontend::execute("", 0, buf).map_err(Error::encode)?;
        frontend::sync(buf);
        Ok(buf.split().freeze())
    })
}

pub fn encode_bind<P, I>(
    statement: &Statement,
    params: I,
    portal: &str,
    buf: &mut BytesMut,
) -> Result<(), Error>
where
    P: BorrowToSql,
    I: IntoIterator<Item = P>,
    I::IntoIter: ExactSizeIterator,
{
    let (param_formats, params): (Vec<_>, Vec<_>) = params
        .into_iter()
        .map(|p| (p.borrow_to_sql().encode_format() as i16, p))
        .unzip();
    let params = params.into_iter();

    assert!(
        statement.params().len() == params.len(),
        "expected {} parameters but got {}",
        statement.params().len(),
        params.len()
    );

    let mut error_idx = 0;
    let r = frontend::bind(
        portal,
        statement.name(),
        param_formats,
        params.zip(statement.params()).enumerate(),
        |(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(ty, buf) {
            Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
            Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
            Err(e) => {
                error_idx = idx;
                Err(e)
            }
        },
        Some(1),
        buf,
    );
    match r {
        Ok(()) => Ok(()),
        Err(frontend::BindError::Conversion(e)) => Err(Error::to_sql(e, error_idx)),
        Err(frontend::BindError::Serialization(e)) => Err(Error::encode(e)),
    }
}

pin_project! {
    /// A stream of table rows.
    pub struct RowStream {
        statement: Statement,
        responses: Responses,
        #[pin]
        _p: PhantomPinned,
    }
}

impl Stream for RowStream {
    type Item = Result<Row, Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let this = self.project();
        loop {
            match ready!(this.responses.poll_next(cx)?) {
                Message::DataRow(body) => {
                    return Poll::Ready(Some(Ok(Row::new(this.statement.clone(), body)?)))
                }
                Message::EmptyQueryResponse
                | Message::CommandComplete(_)
                | Message::PortalSuspended => {}
                Message::ReadyForQuery(_) => return Poll::Ready(None),
                _ => return Poll::Ready(Some(Err(Error::unexpected_message()))),
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Downloads a testnet configuration from Github.

use reqwest;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

const TESTNET_ID: &str = "altona";

fn main() {
    if !base_dir().exists() {
        std::fs::create_dir_all(base_dir())
            .unwrap_or_else(|_| panic!("Unable to create {:?}", base_dir()));

        match get_all_files() {
            Ok(()) => (),
            Err(e) => {
                std::fs::remove_dir_all(base_dir()).unwrap_or_else(|_| panic!(
                    "{}. Failed to remove {:?}, please remove the directory manually because it may contains incomplete testnet data.",
                    e,
                    base_dir(),
                ));
                panic!(e);
            }
        }
    }
}

pub fn get_all_files() -> Result<(), String> {
    get_file("boot_enr.yaml")?;
    get_file("config.yaml")?;
    get_file("deploy_block.txt")?;
    get_file("deposit_contract.txt")?;
    // TODO: add once we know the genesis state for Altona.
    //
    // get_file("genesis.ssz")?;

    Ok(())
}

pub fn get_file(filename: &str) -> Result<(), String> {
    let url = format!(
        "https://raw.githubusercontent.com/sigp/witti/ff9ff43ba4f15fe50838d832daabd284ab1124df/altona/lighthouse/{}",
        filename
    );

    let path = base_dir().join(filename);
    let mut file =
        File::create(path).map_err(|e| format!("Failed to create {}: {:?}", filename, e))?;

    let request = reqwest::blocking::Client::builder()
        .build()
        .map_err(|_| "Could not build request client".to_string())?
        .get(&url)
        .timeout(std::time::Duration::from_secs(120));

    let contents = request
        .send()
        .map_err(|e| format!("Failed to download {}: {}", filename, e))?
        .error_for_status()
        .map_err(|e| format!("Error downloading {}: {}", filename, e))?
        .bytes()
        .map_err(|e| format!("Failed to read {} response bytes: {}", filename, e))?;

    file.write(&contents)
        .map_err(|e| format!("Failed to write to {}: {:?}", filename, e))?;

    Ok(())
}

fn base_dir() -> PathBuf {
    env::var("CARGO_MANIFEST_DIR")
        .expect("should know manifest dir")
        .parse::<PathBuf>()
        .expect("should parse manifest dir as path")
        .join(TESTNET_ID)
}
<commit_msg>Update testnet-dir (#1301)<commit_after>//! Downloads a testnet configuration from Github.

use reqwest;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

const TESTNET_ID: &str = "altona";

fn main() {
    if !base_dir().exists() {
        std::fs::create_dir_all(base_dir())
            .unwrap_or_else(|_| panic!("Unable to create {:?}", base_dir()));

        match get_all_files() {
            Ok(()) => (),
            Err(e) => {
                std::fs::remove_dir_all(base_dir()).unwrap_or_else(|_| panic!(
                    "{}. Failed to remove {:?}, please remove the directory manually because it may contains incomplete testnet data.",
                    e,
                    base_dir(),
                ));
                panic!(e);
            }
        }
    }
}

pub fn get_all_files() -> Result<(), String> {
    get_file("boot_enr.yaml")?;
    get_file("config.yaml")?;
    get_file("deploy_block.txt")?;
    get_file("deposit_contract.txt")?;
    // TODO: add once we know the genesis state for Altona.
    //
    // get_file("genesis.ssz")?;

    Ok(())
}

pub fn get_file(filename: &str) -> Result<(), String> {
    let url = format!(
        "https://raw.githubusercontent.com/sigp/witti/a48ea2d68a87db93aa7fd482461418496ed4347d/altona/lighthouse/{}",
        filename
    );

    let path = base_dir().join(filename);
    let mut file =
        File::create(path).map_err(|e| format!("Failed to create {}: {:?}", filename, e))?;

    let request = reqwest::blocking::Client::builder()
        .build()
        .map_err(|_| "Could not build request client".to_string())?
        .get(&url)
        .timeout(std::time::Duration::from_secs(120));

    let contents = request
        .send()
        .map_err(|e| format!("Failed to download {}: {}", filename, e))?
        .error_for_status()
        .map_err(|e| format!("Error downloading {}: {}", filename, e))?
        .bytes()
        .map_err(|e| format!("Failed to read {} response bytes: {}", filename, e))?;

    file.write(&contents)
        .map_err(|e| format!("Failed to write to {}: {:?}", filename, e))?;

    Ok(())
}

fn base_dir() -> PathBuf {
    env::var("CARGO_MANIFEST_DIR")
        .expect("should know manifest dir")
        .parse::<PathBuf>()
        .expect("should parse manifest dir as path")
        .join(TESTNET_ID)
}
<|endoftext|>


<commit_before>//! A trait for window operations.

use event;
use game_window_settings::GameWindowSettings;

/// Implemented by window back-end.
pub trait GameWindow {
    /// Get the window's settings.
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings;

    /// Returns ture if the window should close.
    fn should_close(&self) -> bool;

    /// Get the window's size
    fn get_size(&self) -> (u32, u32) {
        (self.get_settings().size[0], self.get_settings().size[1])
    }

    /// swap buffers.
    fn swap_buffers(&self) {}

    /// Poll a event from window's event queue.
    fn poll_event(&mut self) -> event::Event { event::NoEvent }
}

/// For use in seperate render threads, implemented by window back-end.
pub trait RenderWindow {
    /// Swap buffers.
    fn swap_buffers(&self) {}
}
<commit_msg>Added `capture_cursor`<commit_after>//! A trait for window operations.

use event;
use game_window_settings::GameWindowSettings;

/// Implemented by window back-end.
pub trait GameWindow {
    /// Get the window's settings.
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings;

    /// Returns ture if the window should close.
    fn should_close(&self) -> bool;

    /// Get the window's size
    fn get_size(&self) -> (u32, u32) {
        (self.get_settings().size[0], self.get_settings().size[1])
    }

    /// Swap buffers.
    fn swap_buffers(&self) {}

    /// When the cursor is captured,
    /// it is hidden and the cursor position does not change.
    /// Only relative mouse motion is registered.
    fn capture_cursor(&mut self, _enabled: bool) {}

    /// Poll a event from window's event queue.
    fn poll_event(&mut self) -> event::Event { event::NoEvent }
}

/// For use in seperate render threads, implemented by window back-end.
pub trait RenderWindow {
    /// Swap buffers.
    fn swap_buffers(&self) {}
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use graph::Subscriptions;

/// TreeNode keeping information about individual nodes information
/// Including subscribed events, channels, groups list
pub struct TreeNode {
    // Token for this Node
    token: String,
    // Prime value for this Node
    value: u64,
    // List of node tokens who are connected to this Node
    relations: Vec<String>
}

/// Graph struct is the main structure for keeping tree state information
/// And keeping events, channels, group names for tree
pub struct Graph {
    // Map of Nodes inside this Graph
    // Key -> Node Token
    // Value -> TreeNode
    nodes: BTreeMap<String, TreeNode>,

    // Events Map inside this Graph
    // Key -> Event Name
    // Value -> Node Token
    events: Subscriptions,

    // Channels Map inside this Graph
    // Key -> Channel Name
    // Value -> Node Token
    channels: Subscriptions,

    // Groups Map inside this Graph
    // Key -> Group Name
    // Value -> Channel Name
    groups: Subscriptions,
}<commit_msg>defining base structs for Graph functionality<commit_after>use std::collections::BTreeMap;

use graph::Subscriptions;

/// TreeNode keeping information about individual nodes information
/// Including subscribed events, channels, groups list
pub struct TreeNode {
    // Token for this Node
    token: String,
    // Prime value for this Node
    value: u64,
    // List of node tokens who are connected to this Node
    relations: Vec<String>
}

/// Graph struct is the main structure for keeping tree state information
/// And keeping events, channels, group names for tree
pub struct Graph {
    // Map of Nodes inside this Graph
    // Key -> Node Token
    // Value -> TreeNode
    nodes: BTreeMap<String, TreeNode>,

    // Events Map inside this Graph
    // Key -> Event Name
    // Value -> Node Token
    events: Subscriptions,

    // Channels Map inside this Graph
    // Key -> Channel Name
    // Value -> Node Token
    channels: Subscriptions,

    // Groups Map inside this Graph
    // Key -> Group Name
    // Value -> Channel Name
    groups: Subscriptions,
}

impl Graph {
    /// Creating new graph system for current Node
    fn new() -> Graph {
        Graph {
            nodes: BTreeMap::new(),
            events: Subscriptions::new(),
            channels: Subscriptions::new(),
            groups: Subscriptions::new()
        }
    }
}<|endoftext|>


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

//! Helpers for reading directory structures from the local filesystem.

use std::sync;
use std::sync::atomic;
use std::os::{last_os_error};
use std::io::{TypeDirectory};
use std::io::fs::{lstat};
use std::io::timer;
use std::time;

use std::c_str::CString;
use libc::funcs::posix88::dirent;
use libc::types::common::posix88::{DIR,dirent_t};
use libc::types::os::arch::c95::c_char;
use libc::{c_int};

pub struct DirIterator {
  fd: *mut DIR,
}

impl DirIterator {
  pub fn new(path: Path) -> Result<DirIterator, String> {
    let fd = path.with_c_str(|c_str| unsafe { dirent::opendir(c_str) });

    if fd as int > 0 { Ok(DirIterator{fd:fd}) }
    else { Err(last_os_error()) }
  }

  fn read(&mut self) -> String {
    extern {
      fn rust_dirent_t_size() -> c_int;
      fn rust_list_dir_val(ptr: *mut dirent_t) -> *const c_char;
    }

    let mut entry_ptr = 0 as *mut dirent_t;

    let size = unsafe { rust_dirent_t_size() };
    let mut buf = Vec::<u8>::with_capacity(size as uint);
    let buf_ptr = buf.as_mut_ptr() as *mut dirent_t;

    let retval = unsafe { dirent::readdir_r(self.fd, buf_ptr, &mut entry_ptr) };

    if retval == 0 && !entry_ptr.is_null() {
      let cstr = unsafe { CString::new(rust_list_dir_val(entry_ptr), false) };
      cstr.as_str().expect("Path not UTF8.").into_string()
    } else { "".to_string() }

  }

}

impl Drop for DirIterator {
  fn drop(&mut self) {
    unsafe {
      dirent::closedir(self.fd)
    };
  }
}

impl Iterator<String> for DirIterator {
  fn next(&mut self) -> Option<String> {
    let name = self.read();
    if name.len() == 0 { None }
    else { Some(name) }
  }
}

pub trait PathHandler<D> {
  fn handle_path(&mut self, D, Path) -> Option<D>;
}

pub fn iterate_recursively<P: Send + Clone, W: PathHandler<P> + Send + Clone>
  (root: (Path, P), worker: &mut W)
{
  let threads = 5;
  let (push_ch, work_ch) = sync_channel(threads);
  let mut pool = sync::TaskPool::new(threads, || proc(_){()});

  let seq_cst = atomic::SeqCst;  // Sequential consistency access mode
  let running_workers = sync::Arc::new(atomic::AtomicInt::new(0));

  let mut timer = timer::Timer::new().unwrap();
  let timeout = timer.periodic(time::Duration::microseconds(100));

  // Insert the root dir into the queue:
  push_ch.send(root);

  // Master thread:
  loop {
    select! {
      () = timeout.recv() => {},  // Queue is empty: fall-through to see if we are done.
      (root, payload) = work_ch.recv() => {
        let t_worker = worker.clone();
        let t_push_ch = push_ch.clone();

        // Count the pool thread as active:
        let t_running_workers = running_workers.clone();
        t_running_workers.fetch_add(1, seq_cst);

        // Execute the task in a pool thread:
        pool.execute(proc(&()) {
          let mut root = root;
          let mut t_worker = t_worker;
          let res = DirIterator::new(root.clone());
          if res.is_ok() {
            let mut it = res.unwrap();
            for file in it {
              if file != ".".into_string() && file != "..".into_string() {
                let rel_path = Path::new(file);
                root.push(rel_path);
                let dir_opt = t_worker.handle_path(payload.clone(), root.clone());
                if dir_opt.is_some() {
                  t_push_ch.send((root.clone(), dir_opt.unwrap()));
                }
                root.pop();
              }
            }
          }

          // Count this pool thread as idle:
          t_running_workers.fetch_sub(1, seq_cst);
        });
      }
    }
    // We are done when no workers are active (i.e. all tasks are done):
    if running_workers.load(seq_cst) == 0 { break }
  }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
  fn clone(&self) -> PrintPathHandler { PrintPathHandler }
}

impl PathHandler<()> for PrintPathHandler {
  fn handle_path(&mut self, _: (), path: Path) -> Option<()> {
    let filename_opt = path.filename_str();
    println!("{}", path.display());
    match filename_opt {
      Some(".") | Some("..") | None => None,
      Some(_) =>
      match lstat(&path) {
        Ok(ref st) if st.kind == TypeDirectory => Some(()),
        _ => None,
      }
    }
  }
}
<commit_msg>Fix a race condition in listdir caused by the use of periodic for timeout.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Helpers for reading directory structures from the local filesystem.

use std::sync;
use std::sync::atomic;
use std::os::{last_os_error};
use std::io::{TypeDirectory};
use std::io::fs::{lstat};

use std::c_str::CString;
use libc::funcs::posix88::dirent;
use libc::types::common::posix88::{DIR,dirent_t};
use libc::types::os::arch::c95::c_char;
use libc::{c_int};

pub struct DirIterator {
  fd: *mut DIR,
}

impl DirIterator {
  pub fn new(path: Path) -> Result<DirIterator, String> {
    let fd = path.with_c_str(|c_str| unsafe { dirent::opendir(c_str) });

    if fd as int > 0 { Ok(DirIterator{fd:fd}) }
    else { Err(last_os_error()) }
  }

  fn read(&mut self) -> String {
    extern {
      fn rust_dirent_t_size() -> c_int;
      fn rust_list_dir_val(ptr: *mut dirent_t) -> *const c_char;
    }

    let mut entry_ptr = 0 as *mut dirent_t;

    let size = unsafe { rust_dirent_t_size() };
    let mut buf = Vec::<u8>::with_capacity(size as uint);
    let buf_ptr = buf.as_mut_ptr() as *mut dirent_t;

    let retval = unsafe { dirent::readdir_r(self.fd, buf_ptr, &mut entry_ptr) };

    if retval == 0 && !entry_ptr.is_null() {
      let cstr = unsafe { CString::new(rust_list_dir_val(entry_ptr), false) };
      cstr.as_str().expect("Path not UTF8.").into_string()
    } else { "".to_string() }

  }

}

impl Drop for DirIterator {
  fn drop(&mut self) {
    unsafe {
      dirent::closedir(self.fd)
    };
  }
}

impl Iterator<String> for DirIterator {
  fn next(&mut self) -> Option<String> {
    let name = self.read();
    if name.len() == 0 { None }
    else { Some(name) }
  }
}

pub trait PathHandler<D> {
  fn handle_path(&mut self, D, Path) -> Option<D>;
}

pub fn iterate_recursively<P: Send + Clone, W: PathHandler<P> + Send + Clone>
  (root: (Path, P), worker: &mut W)
{
  let threads = 5;
  let (push_ch, work_ch) = sync_channel(threads);
  let mut pool = sync::TaskPool::new(threads, || proc(_){()});

  let seq_cst = atomic::SeqCst;  // Sequentially consistent access mode
  let running_workers = sync::Arc::new(atomic::AtomicInt::new(0));

  // Insert the first task into the queue:
  push_ch.send(Some(root));

  // Master thread:
  loop {
    match work_ch.recv() {
      None => {
        // A worker has reached completion and has decremented the counter.
        // We are done when no more workers are active (i.e. all tasks are done):
        if running_workers.load(seq_cst) == 0 {
          break
        }
      },
      Some((root, payload)) => {
        let t_worker = worker.clone();
        let t_push_ch = push_ch.clone();

        // Count the pool thread as active:
        let t_running_workers = running_workers.clone();
        t_running_workers.fetch_add(1, seq_cst);

        // Execute the task in a pool thread:
        pool.execute(proc(&()) {
          let mut root = root;
          let mut t_worker = t_worker;
          let res = DirIterator::new(root.clone());
          if res.is_ok() {
            let mut it = res.unwrap();
            for file in it {
              if file != ".".into_string() && file != "..".into_string() {
                let rel_path = Path::new(file);
                root.push(rel_path);
                let dir_opt = t_worker.handle_path(payload.clone(), root.clone());
                if dir_opt.is_some() {
                  t_push_ch.send(Some((root.clone(), dir_opt.unwrap())));
                }
                root.pop();
              }
            }
          }

          // Count this pool thread as idle:
          t_running_workers.fetch_sub(1, seq_cst);
          t_push_ch.send(None)
        });
      }
    }
  }
}

struct PrintPathHandler;

impl Clone for PrintPathHandler {
  fn clone(&self) -> PrintPathHandler { PrintPathHandler }
}

impl PathHandler<()> for PrintPathHandler {
  fn handle_path(&mut self, _: (), path: Path) -> Option<()> {
    let filename_opt = path.filename_str();
    println!("{}", path.display());
    match filename_opt {
      Some(".") | Some("..") | None => None,
      Some(_) =>
      match lstat(&path) {
        Ok(ref st) if st.kind == TypeDirectory => Some(()),
        _ => None,
      }
    }
  }
}
<|endoftext|>


<commit_before>extern crate hyper;

use std::thread;

use self::hyper::server;

use http::dispatcher::Dispatcher;
use http::app_manager::AppManager;

pub struct Server {
    pub thread: thread::JoinHandle<()>,
}

impl Server {
    pub fn create() -> Server {
        let thread = Server::create_thread();

        Server{
            thread: thread,
        }
    }

    fn create_thread() -> thread::JoinHandle<()> {
        thread::spawn(move || {
            let app_manager = AppManager::new();
            let dispatcher = Dispatcher::new(app_manager);

            server::Server::http("127.0.0.1:12044").unwrap().handle(dispatcher).unwrap();
        })
    }
}

<commit_msg>feature: Increase number of threads to 20<commit_after>extern crate hyper;

use std::thread;

use self::hyper::server;

use http::dispatcher::Dispatcher;
use http::app_manager::AppManager;

pub struct Server {
    pub thread: thread::JoinHandle<()>,
}

impl Server {
    pub fn create() -> Server {
        let thread = Server::create_thread();

        Server{
            thread: thread,
        }
    }

    fn create_thread() -> thread::JoinHandle<()> {
        thread::spawn(move || {
            let app_manager = AppManager::new();
            let dispatcher = Dispatcher::new(app_manager);

            server::Server::http("127.0.0.1:12044").unwrap().handle_threads(dispatcher, 20).unwrap();
        })
    }
}

<|endoftext|>


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

/// Creates operator implementations for a Filter struct
/// Currently only Fn and Filter implementations are handled
///
/// Takes at least two arguments: the struct to implement the traits for, and
/// the block to define the filter function. Preceeding the block should be the
/// variables for self and the passed in argument to filter, separated by spaces.
/// After that, any filter generics needed for the struct should be specified.
///
/// # Examples
///
/// ```
/// # #![cfg_attr(feature = "unstable-filter-as-fn", feature(unboxed_closures, fn_traits))]
/// # #[macro_use] extern crate filters;
/// # use filters::filter::Filter;
/// # fn main() {
/// struct Or<T, U> {
///     a: T,
///     b: U
/// }
///
/// impl_operators!(Or, self e { self.a.filter(e) || self.b.filter(e) }, T, U);
///
/// let or = Or {a: |&x: &i32| x < 5, b: |&x: &i32| x > 10};
/// assert_eq!(or.filter(&0), true);
/// assert_eq!(or.filter(&7), false);
/// assert_eq!(or.filter(&15), true);
/// // If unstable-filter-as-fn is enabled `or` will also be a Fn(&i32) -> bool
/// # }
/// ```
#[macro_export]
macro_rules! impl_operators {
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl:block, $( $generic:ident ),*) => {
        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnOnce<(&'a I,)> for $struct_ident<$( $generic, )*> {
            type Output = bool;
            extern "rust-call" fn call_once<'b>(self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnMut<(&'a I,)> for $struct_ident<$( $generic, )*> {
            extern "rust-call" fn call_mut<'b>(&mut self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> Fn<(&'a I,)> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            extern "rust-call" fn call<'b>(&$self_var, ($arg_var,): (&'a I,)) -> Self::Output $filter_impl
        }

        #[cfg(not(feature = "unstable-filter-as-fn"))]
        impl<I, $( $generic: Filter<I>, )*> Filter<I> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            fn filter(&$self_var, $arg_var: &I) -> bool $filter_impl
        }
    };
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl: block) => {
        impl_operators!($struct_ident, $self_var $arg_var $filter_impl, );
    };
}
<commit_msg>Add macro to generate failable filter implementation<commit_after>//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

/// Creates operator implementations for a Filter struct
/// Currently only Fn and Filter implementations are handled
///
/// Takes at least two arguments: the struct to implement the traits for, and
/// the block to define the filter function. Preceeding the block should be the
/// variables for self and the passed in argument to filter, separated by spaces.
/// After that, any filter generics needed for the struct should be specified.
///
/// # Examples
///
/// ```
/// # #![cfg_attr(feature = "unstable-filter-as-fn", feature(unboxed_closures, fn_traits))]
/// # #[macro_use] extern crate filters;
/// # use filters::filter::Filter;
/// # fn main() {
/// struct Or<T, U> {
///     a: T,
///     b: U
/// }
///
/// impl_operators!(Or, self e { self.a.filter(e) || self.b.filter(e) }, T, U);
///
/// let or = Or {a: |&x: &i32| x < 5, b: |&x: &i32| x > 10};
/// assert_eq!(or.filter(&0), true);
/// assert_eq!(or.filter(&7), false);
/// assert_eq!(or.filter(&15), true);
/// // If unstable-filter-as-fn is enabled `or` will also be a Fn(&i32) -> bool
/// # }
/// ```
#[macro_export]
macro_rules! impl_operators {
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl:block, $( $generic:ident ),*) => {
        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnOnce<(&'a I,)> for $struct_ident<$( $generic, )*> {
            type Output = bool;
            extern "rust-call" fn call_once<'b>(self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnMut<(&'a I,)> for $struct_ident<$( $generic, )*> {
            extern "rust-call" fn call_mut<'b>(&mut self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> Fn<(&'a I,)> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            extern "rust-call" fn call<'b>(&$self_var, ($arg_var,): (&'a I,)) -> Self::Output $filter_impl
        }

        #[cfg(not(feature = "unstable-filter-as-fn"))]
        impl<I, $( $generic: Filter<I>, )*> Filter<I> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            fn filter(&$self_var, $arg_var: &I) -> bool $filter_impl
        }
    };
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl: block) => {
        impl_operators!($struct_ident, $self_var $arg_var $filter_impl, );
    };
}

/// Variant of impl_operators!() macro for FailableFilter types
#[macro_export]
macro_rules! impl_failable_operators {
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl:block, $( $generic:ident ),*) => {
        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnOnce<(&'a I,)> for $struct_ident<$( $generic, )*> {
            type Output = Result<bool, Error>;
            extern "rust-call" fn call_once<'b>(self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> FnMut<(&'a I,)> for $struct_ident<$( $generic, )*> {
            extern "rust-call" fn call_mut<'b>(&mut self, (arg,): (&'a I,)) -> Self::Output {
                self.filter(arg)
            }
        }

        #[cfg(feature = "unstable-filter-as-fn")]
        impl<'a, I, $( $generic: Filter<I>, )*> Fn<(&'a I,)> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            extern "rust-call" fn call<'b>(&$self_var, ($arg_var,): (&'a I,)) -> Self::Output $filter_impl
        }

        #[cfg(not(feature = "unstable-filter-as-fn"))]
        impl<I, $( $generic: FailableFilter<I>, )*> FailableFilter<I> for $struct_ident<$( $generic, )*> {
            #[allow(unused_variables)]
            fn filter(&$self_var, $arg_var: &I) -> Result<bool, Error> $filter_impl
        }
    };
    ($struct_ident:ident, $self_var: ident $arg_var: ident $filter_impl: block) => {
        impl_operators!($struct_ident, $self_var $arg_var $filter_impl, );
    };
}

<|endoftext|>


<commit_before>
use size_hint;
use Itertools;

use std::mem::replace;

macro_rules! clone_fields {
    ($name:ident, $base:expr, $($field:ident),+) => (
        $name {
            $(
                $field : $base . $field .clone()
            ),*
        }
    );
}

/// Head element and Tail iterator pair
///
/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
/// first items (which are guaranteed to exist).
///
/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
/// `KMerge` into a min-heap.
#[derive(Debug)]
struct HeadTail<I>
    where I: Iterator
{
    head: I::Item,
    tail: I,
}

impl<I> HeadTail<I>
    where I: Iterator
{
    /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
    fn new(mut it: I) -> Option<HeadTail<I>> {
        let head = it.next();
        head.map(|h| {
            HeadTail {
                head: h,
                tail: it,
            }
        })
    }

    /// Get the next element and update `head`, returning the old head in `Some`.
    ///
    /// Returns `None` when the tail is exhausted (only `head` then remains).
    fn next(&mut self) -> Option<I::Item> {
        if let Some(next) = self.tail.next() {
            Some(replace(&mut self.head, next))
        } else {
            None
        }
    }

    /// Hints at the size of the sequence, same as the `Iterator` method.
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.tail.size_hint(), 1)
    }
}

impl<I> Clone for HeadTail<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> Self {
        clone_fields!(HeadTail, self, head, tail)
    }
}

/// Make `data` a heap (min-heap w.r.t the sorting).
fn heapify<T, S>(data: &mut [T], mut less_than: S)
    where S: FnMut(&T, &T) -> bool
{
    for i in (0..data.len() / 2).rev() {
        sift_down(data, i, &mut less_than);
    }
}

/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
    where S: FnMut(&T, &T) -> bool
{
    debug_assert!(index <= heap.len());
    let mut pos = index;
    let mut child = 2 * pos + 1;
    // the `pos` conditional is to avoid a bounds check
    while pos < heap.len() && child < heap.len() {
        let right = child + 1;

        // pick the smaller of the two children
        if right < heap.len() && less_than(&heap[right], &heap[child]) {
            child = right;
        }

        // sift down is done if we are already in order
        if !less_than(&heap[child], &heap[pos]) {
            return;
        }
        heap.swap(pos, child);
        pos = child;
        child = 2 * pos + 1;
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
/// If all base iterators are sorted (ascending), the result is sorted.
///
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct KMerge<I>
    where I: Iterator
{
    heap: Vec<HeadTail<I>>,
}

/// Create an iterator that merges elements of the contained iterators using
/// the ordering function.
///
/// Equivalent to `iterable.into_iter().kmerge()`.
///
/// ```
/// use itertools::kmerge;
///
/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
///     /* loop body */
/// }
/// ```
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
    where I: IntoIterator,
          I::Item: IntoIterator,
          <<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
{
    let iter = iterable.into_iter();
    let (lower, _) = iter.size_hint();
    let mut heap = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap, |a, b| a.head < b.head);
    KMerge { heap: heap }
}

impl<I> Clone for KMerge<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> KMerge<I> {
        clone_fields!(KMerge, self, heap)
    }
}

impl<I> Iterator for KMerge<I>
    where I: Iterator,
          I::Item: PartialOrd
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next) = self.heap[0].next() {
            next
        } else {
            self.heap.swap_remove(0).head
        };
        sift_down(&mut self.heap, 0, |a, b| a.head < b.head);
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.heap.iter()
                 .map(|i| i.size_hint())
                 .fold1(size_hint::add)
                 .unwrap_or((0, Some(0)))
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators
/// according to an ordering function.
///
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct KMergeBy<I, F>
    where I: Iterator,
{
    heap: Vec<HeadTail<I>>,
    less_than: F,
}

/// Create an iterator that merges elements of the contained iterators.
///
/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
    -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
    where I: IntoIterator,
          I::Item: IntoIterator,
          F: FnMut(&<<I as IntoIterator>::Item as IntoIterator>::Item,
                   &<<I as IntoIterator>::Item as IntoIterator>::Item) -> bool
{
    let iter = iterable.into_iter();
    let (lower, _) = iter.size_hint();
    let mut heap: Vec<_> = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap, |a, b| less_than(&a.head, &b.head));
    KMergeBy { heap: heap, less_than: less_than }
}

impl<I, F> Iterator for KMergeBy<I, F>
    where I: Iterator,
          F: FnMut(&I::Item, &I::Item) -> bool
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next) = self.heap[0].next() {
            next
        } else {
            self.heap.swap_remove(0).head
        };
        let less_than = &mut self.less_than;
        sift_down(&mut self.heap, 0, |a, b| less_than(&a.head, &b.head));
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.heap.iter()
                 .map(|i| i.size_hint())
                 .fold1(size_hint::add)
                 .unwrap_or((0, Some(0)))
    }
}
<commit_msg>Impl Debug for KMerge<commit_after>
use size_hint;
use Itertools;

use std::mem::replace;
use std::fmt;

macro_rules! clone_fields {
    ($name:ident, $base:expr, $($field:ident),+) => (
        $name {
            $(
                $field : $base . $field .clone()
            ),*
        }
    );
}

/// Head element and Tail iterator pair
///
/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on
/// first items (which are guaranteed to exist).
///
/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in
/// `KMerge` into a min-heap.
#[derive(Debug)]
struct HeadTail<I>
    where I: Iterator
{
    head: I::Item,
    tail: I,
}

impl<I> HeadTail<I>
    where I: Iterator
{
    /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty.
    fn new(mut it: I) -> Option<HeadTail<I>> {
        let head = it.next();
        head.map(|h| {
            HeadTail {
                head: h,
                tail: it,
            }
        })
    }

    /// Get the next element and update `head`, returning the old head in `Some`.
    ///
    /// Returns `None` when the tail is exhausted (only `head` then remains).
    fn next(&mut self) -> Option<I::Item> {
        if let Some(next) = self.tail.next() {
            Some(replace(&mut self.head, next))
        } else {
            None
        }
    }

    /// Hints at the size of the sequence, same as the `Iterator` method.
    fn size_hint(&self) -> (usize, Option<usize>) {
        size_hint::add_scalar(self.tail.size_hint(), 1)
    }
}

impl<I> Clone for HeadTail<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> Self {
        clone_fields!(HeadTail, self, head, tail)
    }
}

/// Make `data` a heap (min-heap w.r.t the sorting).
fn heapify<T, S>(data: &mut [T], mut less_than: S)
    where S: FnMut(&T, &T) -> bool
{
    for i in (0..data.len() / 2).rev() {
        sift_down(data, i, &mut less_than);
    }
}

/// Sift down element at `index` (`heap` is a min-heap wrt the ordering)
fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
    where S: FnMut(&T, &T) -> bool
{
    debug_assert!(index <= heap.len());
    let mut pos = index;
    let mut child = 2 * pos + 1;
    // the `pos` conditional is to avoid a bounds check
    while pos < heap.len() && child < heap.len() {
        let right = child + 1;

        // pick the smaller of the two children
        if right < heap.len() && less_than(&heap[right], &heap[child]) {
            child = right;
        }

        // sift down is done if we are already in order
        if !less_than(&heap[child], &heap[pos]) {
            return;
        }
        heap.swap(pos, child);
        pos = child;
        child = 2 * pos + 1;
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.
/// If all base iterators are sorted (ascending), the result is sorted.
///
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct KMerge<I>
    where I: Iterator
{
    heap: Vec<HeadTail<I>>,
}

impl<I> fmt::Debug for KMerge<I>
    where I: Iterator + fmt::Debug,
          I::Item: fmt::Debug,
{
    debug_fmt_fields!(KMerge, heap);
}

/// Create an iterator that merges elements of the contained iterators using
/// the ordering function.
///
/// Equivalent to `iterable.into_iter().kmerge()`.
///
/// ```
/// use itertools::kmerge;
///
/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) {
///     /* loop body */
/// }
/// ```
pub fn kmerge<I>(iterable: I) -> KMerge<<I::Item as IntoIterator>::IntoIter>
    where I: IntoIterator,
          I::Item: IntoIterator,
          <<I as IntoIterator>::Item as IntoIterator>::Item: PartialOrd
{
    let iter = iterable.into_iter();
    let (lower, _) = iter.size_hint();
    let mut heap = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap, |a, b| a.head < b.head);
    KMerge { heap: heap }
}

impl<I> Clone for KMerge<I>
    where I: Iterator + Clone,
          I::Item: Clone
{
    fn clone(&self) -> KMerge<I> {
        clone_fields!(KMerge, self, heap)
    }
}

impl<I> Iterator for KMerge<I>
    where I: Iterator,
          I::Item: PartialOrd
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next) = self.heap[0].next() {
            next
        } else {
            self.heap.swap_remove(0).head
        };
        sift_down(&mut self.heap, 0, |a, b| a.head < b.head);
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.heap.iter()
                 .map(|i| i.size_hint())
                 .fold1(size_hint::add)
                 .unwrap_or((0, Some(0)))
    }
}

/// An iterator adaptor that merges an abitrary number of base iterators
/// according to an ordering function.
///
/// Iterator element type is `I::Item`.
///
/// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more
/// information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct KMergeBy<I, F>
    where I: Iterator,
{
    heap: Vec<HeadTail<I>>,
    less_than: F,
}

/// Create an iterator that merges elements of the contained iterators.
///
/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`.
pub fn kmerge_by<I, F>(iterable: I, mut less_than: F)
    -> KMergeBy<<I::Item as IntoIterator>::IntoIter, F>
    where I: IntoIterator,
          I::Item: IntoIterator,
          F: FnMut(&<<I as IntoIterator>::Item as IntoIterator>::Item,
                   &<<I as IntoIterator>::Item as IntoIterator>::Item) -> bool
{
    let iter = iterable.into_iter();
    let (lower, _) = iter.size_hint();
    let mut heap: Vec<_> = Vec::with_capacity(lower);
    heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter())));
    heapify(&mut heap, |a, b| less_than(&a.head, &b.head));
    KMergeBy { heap: heap, less_than: less_than }
}

impl<I, F> Iterator for KMergeBy<I, F>
    where I: Iterator,
          F: FnMut(&I::Item, &I::Item) -> bool
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.heap.is_empty() {
            return None;
        }
        let result = if let Some(next) = self.heap[0].next() {
            next
        } else {
            self.heap.swap_remove(0).head
        };
        let less_than = &mut self.less_than;
        sift_down(&mut self.heap, 0, |a, b| less_than(&a.head, &b.head));
        Some(result)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.heap.iter()
                 .map(|i| i.size_hint())
                 .fold1(size_hint::add)
                 .unwrap_or((0, Some(0)))
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

//! This module contains the `Cleaner` traits and various implementations of it.

use std::borrow::Cow;

/// Custom function because we don't really want to touch \t or \n
fn is_whitespace(c: char) -> bool {
    c == ' ' || c == ' ' || c == ' '
}

/// Trait for cleaning a string.
///
/// This trait must be called for text that is e.g. in a paragraph, a title,
/// NOT for code blocks, hyperlinks and so on!
pub trait Cleaner: Sync {
    /// Cleans a string. The default implementation is to remove multiple consecutive whitespaces
    ///
    /// # Argumets
    ///
    /// * `str`: the string that must be cleaned
    /// * `latex`: a bool specifying whether output is Latex code or not
    fn clean<'a>(&self, str: Cow<'a, str>, _latex: bool) -> Cow<'a, str> {
        str
    }
}

/// Cleaner implementation that does nothing
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::Off;
/// use std::borrow::Cow;
/// let off = Off;
/// let s = off.clean(Cow::Borrowed("  A string   that won't be cleaned "), false);
/// assert_eq!(&s, "  A string   that won't be cleaned ");
/// ```
pub struct Off;
impl Cleaner for Off {}

/// Default implementation of cleaner trait.
///
/// Only removes unnecessary whitespaces.
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::Default;
/// use std::borrow::Cow;
/// let s = Default.clean(Cow::Borrowed("  A  string   with   more   whitespaces  than  needed   "), false);
/// assert_eq!(&s, " A string with more whitespaces than needed ");
/// ```
pub struct Default;
impl Cleaner for Default {
    /// Remove unnecessary whitespaces
    fn clean<'a>(&self, s: Cow<'a, str>, _: bool) -> Cow<'a, str> {
        if let Some(first) = s.chars().position(is_whitespace) { // if not, no need to do anything
            let mut chars = s.chars().collect::<Vec<_>>();
            let mut new_s = String::with_capacity(chars.len());
            let rest = chars.split_off(first);
            new_s.push_str(&chars.into_iter().collect::<String>());
            let mut previous_space = false;
            for c in rest {
                if is_whitespace(c) {
                    if previous_space {
                        // previous char already a space, don't copy it
                    } else {
                        new_s.push(c);
                        previous_space = true;
                    }
                } else {
                    previous_space = false;
                    new_s.push(c);
                }
            }

            Cow::Owned(new_s)
        } else {
            s
        }
    }
}

/// Implementation for french 'cleaning'
///
/// This implementation replaces spaces before some characters (e.g. `?` or `;` with non-breaking spaces
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::French;
/// use std::borrow::Cow;
/// let s =  French.clean(Cow::Borrowed("  Bonjour ! Comment allez-vous   ?   "), true);
/// assert_eq!(&s, " Bonjour~! Comment allez-vous~? ");
/// ```
pub struct French;

const THRESHOLD_CURRENCY: usize = 3; // after that, assume it's not a currency
const THRESHOLD_UNIT: usize = 2; // after that, assume it's not a unit
const THRESHOLD_QUOTE: usize = 28; // after that, assume it's a dialogue
const THRESHOLD_REAL_WORD: usize = 3; // after that, can be reasonably sure it is not an abbreviation

impl Cleaner for French {
    /// Puts non breaking spaces before/after `:`, `;`, `?`, `!`, `«`, `»`, `—`
    fn clean<'a>(&self, s: Cow<'a, str>, latex: bool) -> Cow<'a, str> {
        fn is_trouble(c: char) -> bool {
            match c {
                '?'|'!'|';'|':'|'»'|'«'|'—'|'–' | '0'...'9' => true,
                _ => false
            }
        }

        let input = Default.clean(s, latex); // first pass with default impl
        // Find first character that is trouble
        let first = input.chars().position(is_trouble);
        if first.is_none() {
            return input;
        }
        let first = first.unwrap();
        let nb_char = if latex {
            '~'
        } else {
            ' ' // non breaking space
        };
        let nb_char_narrow = if latex {
            '~'
        } else {
            '\u{202F}' // narrow non breaking space
        };
        let nb_char_em = if latex {
            '~'
        } else {
            '\u{2002}' // demi em space
        };

        // Find first char `c` in slice `v` after index `n`
        fn find_next(v: &[char], c: char, n: usize) -> Option<usize> {
            for i in n..v.len() {
                if v[i] == c  {
                    return Some(i);
                }
            }
            None
        }

        // Return true if next non whitespace char in `v` after index `n` is uppercase
        fn is_next_char_uppercase(v: &[char], n: usize)-> bool {
            for i in n..v.len() {
                if v[i].is_whitespace() {
                    continue;
                }
                if v[i].is_uppercase() {
                    return true;
                }
                if v[i].is_lowercase() {
                    return false;
                }
            }
            false
        }

        // Return true(some) if a closing dash was found before what looks like the end of a sentence, None else
        fn find_closing_dash(v: &[char], n: usize) -> Option<usize> {
            let mut word = String::new();
            for j in n..v.len() {
                match v[j] {

                    '!' | '?' => if is_next_char_uppercase(v, j+1) {
                        return None;
                    },
                    '-' | '–' | '—' => if v[j-1].is_whitespace() {
                        return Some(j-1);
                    },
                    '.' => if !is_next_char_uppercase(v, j+1) {
                        continue;
                    } else {
                        if let Some(c) = word.chars().next() {
                            if !c.is_uppercase() {
                                return None;
                            } else {
                                if word.len() > THRESHOLD_REAL_WORD {
                                    return None;
                                }
                            }
                        }
                    },
                    c if c.is_whitespace() => word = String::new(),
                    c => word.push(c),
                }
            }
            return None;
        }

        /// Returns the next word in `v` starting from index `n`
        fn get_next_word(v: &[char], n: usize) -> &[char] {
            let mut beginning = n;
            let mut end = v.len();

            for i in n..v.len() {
                if v[i].is_alphabetic() {
                    beginning = i;
                    break;
                }
            }

            for i in beginning..v.len() {
                if v[i].is_whitespace() {
                    end = i-1;
                    break;
                }
            }

            &v[beginning..end]
        }

        /// Return true if the character is a symbol that is used after number and should have a nb_char before
        fn char_is_symbol(v: &[char], i: usize) -> bool {
            let is_next_letter = if i < v.len() - 1 {
                v[i+1].is_alphabetic()
            } else {
                false
            };
            if is_next_letter {
                match v[i] {
                    '°' => true,
                    c if c.is_uppercase() => {
                        let word = get_next_word(v, i);
                        if word.len() > THRESHOLD_CURRENCY {
                            // not a currency
                            false
                        } else {
                            // if all uppercase and less than THRESHOLD, assume it's a currency or a unit
                            word.iter().all(|c| c.is_uppercase())
                        }
                    },
                    c if c.is_alphabetic() => {
                        let word = get_next_word(v, i);
                        // if two letters, assume it is a unit
                        word.len() <= THRESHOLD_UNIT
                    },
                    _ => false
                }
            } else {
                match v[i] {
                    c if (!c.is_alphabetic() && !c.is_whitespace()) => true, // special symbol
                    c if c.is_uppercase() => true, //single uppercase letter
                    _ => false,
                }
            }
        }

        let mut found_opening_quote = false; // we didn't find an opening quote yet
        let mut chars = input.chars().collect::<Vec<_>>();
        let mut is_number_series = false;

        // Get back one step
        let first = if first > 1 {
            first - 1
        } else {
            0
        };

        for i in first..(chars.len()-1) {
            // Handle numbers (that's easy)
            let current = chars[i];
            let next = chars[i+1];

            match current {
                '0'...'9' => if i == 0 {
                    is_number_series = true;
                } else if !chars[i-1].is_alphabetic() {
                    is_number_series = true;
                },
                c if c.is_whitespace() => {
                    if is_number_series && (next.is_digit(10) || char_is_symbol(&chars, i+1)) {
                        // Next char is a number or symbol such as $, and previous was number
                        chars[i] = nb_char_narrow;
                    }
                },
                _ => { is_number_series = false; }
            }
        }

        for i in first..(chars.len()-1) {
            let current = chars[i];
            let next = chars[i+1];

            // Handle the rest (that's hard)
            if is_whitespace(current) {
                match next {
                    // handle narrow nb space before char
                    '?' | '!' | ';' => chars[i] = nb_char_narrow,
                    ':' => chars[i] = nb_char,
                    '»' => if current == ' ' {
                        // Assumne that if it isn't a normal space it was used here for good reason, don't replace it
                        if found_opening_quote {
                            // not the end of a dialogue
                            chars[i] = nb_char;
                        } else {
                            chars[i] = nb_char;
                        }
                    },
                    _ => (),
                }
            } else {
                match current {
                    // handle nb space after char
                    '—' | '«' | '-' | '–' => {
                        if is_whitespace(next) {
                            let replacing_char = match current {
                                '—' | '-' | '–' => {
                                    if i <= 1 {
                                        nb_char_em
                                    } else {
                                        if chars[i-1] == nb_char {
                                            // non breaking space before, so probably should have a breakable one after
                                            ' '
                                        } else {
                                            if let Some(closing) = find_closing_dash(&chars, i+1) {
                                                chars[closing] = nb_char;
                                            }
                                            nb_char
                                        }
                                    }
                                },
                                '«' => {
                                    found_opening_quote = true;
                                    if i <= 1 {
                                        nb_char
                                    } else {
                                        let j = find_next(&chars, '»', i);
                                        if let Some(j) = j {
                                            if chars[j-1].is_whitespace() {
                                                if j >= chars.len() - 1 {
                                                    // » is at the end, assume it is a dialogue
                                                    chars[j-1] = nb_char;
                                                    nb_char
                                                } else {
                                                    if j - i > THRESHOLD_QUOTE {
                                                        // It's a quote, so use large space?
                                                        chars[j-1] = nb_char;
                                                        nb_char
                                                    } else {
                                                        // Not long enough to be a quote, use narrow nb char
                                                        chars[j-1] = nb_char_narrow;
                                                        nb_char_narrow
                                                    }
                                                }
                                            } else {
                                                // wtf formatting?
                                                nb_char
                                            }
                                        } else {
                                            // No ending quote found, assume is a dialogue
                                            nb_char
                                        }
                                    }
                                }, // TODO: better heuristic: use narrow nb_char if not at front???
                                _ => unreachable!(),
                            };
                            chars[i+1] = replacing_char;
                        }
                    }
                    _ => (),
                }
            }
        }
        Cow::Owned(chars.into_iter().collect())
    }
}

<commit_msg>Revert "Try to optimize default cleaner"<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

//! This module contains the `Cleaner` traits and various implementations of it.

use std::borrow::Cow;

/// Custom function because we don't really want to touch \t or \n
fn is_whitespace(c: char) -> bool {
    c == ' ' || c == ' ' || c == ' '
}

/// Trait for cleaning a string.
///
/// This trait must be called for text that is e.g. in a paragraph, a title,
/// NOT for code blocks, hyperlinks and so on!
pub trait Cleaner: Sync {
    /// Cleans a string. The default implementation is to remove multiple consecutive whitespaces
    ///
    /// # Argumets
    ///
    /// * `str`: the string that must be cleaned
    /// * `latex`: a bool specifying whether output is Latex code or not
    fn clean<'a>(&self, str: Cow<'a, str>, _latex: bool) -> Cow<'a, str> {
        str
    }
}

/// Cleaner implementation that does nothing
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::Off;
/// use std::borrow::Cow;
/// let off = Off;
/// let s = off.clean(Cow::Borrowed("  A string   that won't be cleaned "), false);
/// assert_eq!(&s, "  A string   that won't be cleaned ");
/// ```
pub struct Off;
impl Cleaner for Off {}

/// Default implementation of cleaner trait.
///
/// Only removes unnecessary whitespaces.
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::Default;
/// use std::borrow::Cow;
/// let s = Default.clean(Cow::Borrowed("  A  string   with   more   whitespaces  than  needed   "), false);
/// assert_eq!(&s, " A string with more whitespaces than needed ");
/// ```
pub struct Default;
impl Cleaner for Default {
    /// Remove unnecessary whitespaces
    fn clean<'a>(&self, s: Cow<'a, str>, _: bool) -> Cow<'a, str> {
        if s.contains(is_whitespace) { // if not, no need to do anything
            let mut new_s = String::with_capacity(s.len());
            let mut previous_space = false;
            for c in s.chars() {
                if is_whitespace(c) {
                    if previous_space {
                        // previous char already a space, don't copy it
                    } else {
                        new_s.push(c);
                        previous_space = true;
                    }
                } else {
                    previous_space = false;
                    new_s.push(c);
                }
            }

            Cow::Owned(new_s)
        } else {
            s
        }
    }
}

/// Implementation for french 'cleaning'
///
/// This implementation replaces spaces before some characters (e.g. `?` or `;` with non-breaking spaces
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::French;
/// use std::borrow::Cow;
/// let s =  French.clean(Cow::Borrowed("  Bonjour ! Comment allez-vous   ?   "), true);
/// assert_eq!(&s, " Bonjour~! Comment allez-vous~? ");
/// ```
pub struct French;

const THRESHOLD_CURRENCY: usize = 3; // after that, assume it's not a currency
const THRESHOLD_UNIT: usize = 2; // after that, assume it's not a unit
const THRESHOLD_QUOTE: usize = 28; // after that, assume it's a dialogue
const THRESHOLD_REAL_WORD: usize = 3; // after that, can be reasonably sure it is not an abbreviation

impl Cleaner for French {
    /// Puts non breaking spaces before/after `:`, `;`, `?`, `!`, `«`, `»`, `—`
    fn clean<'a>(&self, s: Cow<'a, str>, latex: bool) -> Cow<'a, str> {
        fn is_trouble(c: char) -> bool {
            match c {
                '?'|'!'|';'|':'|'»'|'«'|'—'|'–' | '0'...'9' => true,
                _ => false
            }
        }

        let input = Default.clean(s, latex); // first pass with default impl
        // Find first character that is trouble
        let first = input.chars().position(is_trouble);
        if first.is_none() {
            return input;
        }
        let first = first.unwrap();
        let nb_char = if latex {
            '~'
        } else {
            ' ' // non breaking space
        };
        let nb_char_narrow = if latex {
            '~'
        } else {
            '\u{202F}' // narrow non breaking space
        };
        let nb_char_em = if latex {
            '~'
        } else {
            '\u{2002}' // demi em space
        };

        // Find first char `c` in slice `v` after index `n`
        fn find_next(v: &[char], c: char, n: usize) -> Option<usize> {
            for i in n..v.len() {
                if v[i] == c  {
                    return Some(i);
                }
            }
            None
        }

        // Return true if next non whitespace char in `v` after index `n` is uppercase
        fn is_next_char_uppercase(v: &[char], n: usize)-> bool {
            for i in n..v.len() {
                if v[i].is_whitespace() {
                    continue;
                }
                if v[i].is_uppercase() {
                    return true;
                }
                if v[i].is_lowercase() {
                    return false;
                }
            }
            false
        }

        // Return true(some) if a closing dash was found before what looks like the end of a sentence, None else
        fn find_closing_dash(v: &[char], n: usize) -> Option<usize> {
            let mut word = String::new();
            for j in n..v.len() {
                match v[j] {

                    '!' | '?' => if is_next_char_uppercase(v, j+1) {
                        return None;
                    },
                    '-' | '–' | '—' => if v[j-1].is_whitespace() {
                        return Some(j-1);
                    },
                    '.' => if !is_next_char_uppercase(v, j+1) {
                        continue;
                    } else {
                        if let Some(c) = word.chars().next() {
                            if !c.is_uppercase() {
                                return None;
                            } else {
                                if word.len() > THRESHOLD_REAL_WORD {
                                    return None;
                                }
                            }
                        }
                    },
                    c if c.is_whitespace() => word = String::new(),
                    c => word.push(c),
                }
            }
            return None;
        }

        /// Returns the next word in `v` starting from index `n`
        fn get_next_word(v: &[char], n: usize) -> &[char] {
            let mut beginning = n;
            let mut end = v.len();

            for i in n..v.len() {
                if v[i].is_alphabetic() {
                    beginning = i;
                    break;
                }
            }

            for i in beginning..v.len() {
                if v[i].is_whitespace() {
                    end = i-1;
                    break;
                }
            }

            &v[beginning..end]
        }

        /// Return true if the character is a symbol that is used after number and should have a nb_char before
        fn char_is_symbol(v: &[char], i: usize) -> bool {
            let is_next_letter = if i < v.len() - 1 {
                v[i+1].is_alphabetic()
            } else {
                false
            };
            if is_next_letter {
                match v[i] {
                    '°' => true,
                    c if c.is_uppercase() => {
                        let word = get_next_word(v, i);
                        if word.len() > THRESHOLD_CURRENCY {
                            // not a currency
                            false
                        } else {
                            // if all uppercase and less than THRESHOLD, assume it's a currency or a unit
                            word.iter().all(|c| c.is_uppercase())
                        }
                    },
                    c if c.is_alphabetic() => {
                        let word = get_next_word(v, i);
                        // if two letters, assume it is a unit
                        word.len() <= THRESHOLD_UNIT
                    },
                    _ => false
                }
            } else {
                match v[i] {
                    c if (!c.is_alphabetic() && !c.is_whitespace()) => true, // special symbol
                    c if c.is_uppercase() => true, //single uppercase letter
                    _ => false,
                }
            }
        }

        let mut found_opening_quote = false; // we didn't find an opening quote yet
        let mut chars = input.chars().collect::<Vec<_>>();
        let mut is_number_series = false;

        // Get back one step
        let first = if first > 1 {
            first - 1
        } else {
            0
        };

        for i in first..(chars.len()-1) {
            // Handle numbers (that's easy)
            let current = chars[i];
            let next = chars[i+1];

            match current {
                '0'...'9' => if i == 0 {
                    is_number_series = true;
                } else if !chars[i-1].is_alphabetic() {
                    is_number_series = true;
                },
                c if c.is_whitespace() => {
                    if is_number_series && (next.is_digit(10) || char_is_symbol(&chars, i+1)) {
                        // Next char is a number or symbol such as $, and previous was number
                        chars[i] = nb_char_narrow;
                    }
                },
                _ => { is_number_series = false; }
            }
        }

        for i in first..(chars.len()-1) {
            let current = chars[i];
            let next = chars[i+1];

            // Handle the rest (that's hard)
            if is_whitespace(current) {
                match next {
                    // handle narrow nb space before char
                    '?' | '!' | ';' => chars[i] = nb_char_narrow,
                    ':' => chars[i] = nb_char,
                    '»' => if current == ' ' {
                        // Assumne that if it isn't a normal space it was used here for good reason, don't replace it
                        if found_opening_quote {
                            // not the end of a dialogue
                            chars[i] = nb_char;
                        } else {
                            chars[i] = nb_char;
                        }
                    },
                    _ => (),
                }
            } else {
                match current {
                    // handle nb space after char
                    '—' | '«' | '-' | '–' => {
                        if is_whitespace(next) {
                            let replacing_char = match current {
                                '—' | '-' | '–' => {
                                    if i <= 1 {
                                        nb_char_em
                                    } else {
                                        if chars[i-1] == nb_char {
                                            // non breaking space before, so probably should have a breakable one after
                                            ' '
                                        } else {
                                            if let Some(closing) = find_closing_dash(&chars, i+1) {
                                                chars[closing] = nb_char;
                                            }
                                            nb_char
                                        }
                                    }
                                },
                                '«' => {
                                    found_opening_quote = true;
                                    if i <= 1 {
                                        nb_char
                                    } else {
                                        let j = find_next(&chars, '»', i);
                                        if let Some(j) = j {
                                            if chars[j-1].is_whitespace() {
                                                if j >= chars.len() - 1 {
                                                    // » is at the end, assume it is a dialogue
                                                    chars[j-1] = nb_char;
                                                    nb_char
                                                } else {
                                                    if j - i > THRESHOLD_QUOTE {
                                                        // It's a quote, so use large space?
                                                        chars[j-1] = nb_char;
                                                        nb_char
                                                    } else {
                                                        // Not long enough to be a quote, use narrow nb char
                                                        chars[j-1] = nb_char_narrow;
                                                        nb_char_narrow
                                                    }
                                                }
                                            } else {
                                                // wtf formatting?
                                                nb_char
                                            }
                                        } else {
                                            // No ending quote found, assume is a dialogue
                                            nb_char
                                        }
                                    }
                                }, // TODO: better heuristic: use narrow nb_char if not at front???
                                _ => unreachable!(),
                            };
                            chars[i+1] = replacing_char;
                        }
                    }
                    _ => (),
                }
            }
        }
        Cow::Owned(chars.into_iter().collect())
    }
}

<|endoftext|>


<commit_before>//! TODO

use std::str::FromStr;

/// TODO doc
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LineEnding {
    /// TODO
    CRLF,
    /// TODO
    LF,
}

impl LineEnding {
    /// TODO
    #[inline]
    pub const fn as_str(&self) -> &'static str {
        match self {
            Self::CRLF => "\r\n",
            Self::LF => "\n",
        }
    }
}

impl FromStr for LineEnding {
    // TODO add a descriptive error
    type Err = ();

    #[inline]
    fn from_str(s: &str) -> Result<LineEnding, ()> {
        match s {
            "\u{000D}\u{000A}" => Result::Ok(LineEnding::CRLF),
            "\u{000A}" => Result::Ok(LineEnding::LF),
            _ => Result::Err(()),
        }
    }
}

/// TODO
#[derive(Debug, Clone, Copy)]
pub(crate) struct NonEmptyLines<'a>(pub &'a str);

impl<'a> Iterator for NonEmptyLines<'a> {
    type Item = (&'a str, Option<LineEnding>);

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(lf) = self.0.find('\n') {
            if lf == 0 || (lf == 1 && self.0.as_bytes()[lf - 1] == b'\r') {
                self.0 = &self.0[(lf + 1)..];
                continue;
            }
            let trimmed = match self.0.as_bytes()[lf - 1] {
                b'\r' => (&self.0[..(lf - 1)], Some(LineEnding::CRLF)),
                _ => (&self.0[..lf], Some(LineEnding::LF)),
            };
            self.0 = &self.0[(lf + 1)..];
            return Some(trimmed);
        }
        if self.0.len() > 0 {
            let result = Some((self.0, None));
            self.0 = "";
            return result;
        } else {
            return None;
        }
    }
}
<commit_msg>Add module documentation and tests<commit_after>//! Line ending detection and conversion.

use std::fmt::{Debug, Formatter};
use std::str::FromStr;

/// Supported line endings. Like in the Rust's standard library, two
/// line endings are supported: `\r\n` and `\n`
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LineEnding {
    /// _Carriage return and line feed_ – a line ending sequence
    /// historically used in _Windows_. Corresponds to the sequence
    /// of ASCII control characters `0x0D 0x0A` or `\r\n`
    CRLF,
    /// _Line feed_ – a line ending historically used in _Unix_.
    ///  Corresponds to the ASCII control character `0x0A` or `\n`
    LF,
}

/// Returned when attempted creating [`LineEnding`] value from an
/// unsupported `&str` value
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UnsupportedLineEnding;

impl std::fmt::Display for UnsupportedLineEnding {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "unsupported line ending sequence")
    }
}

impl std::error::Error for UnsupportedLineEnding {}

impl LineEnding {
    /// Turns this [`LineEnding`] value into its ASCII representation.
    #[inline]
    pub const fn as_str(&self) -> &'static str {
        match self {
            Self::CRLF => "\r\n",
            Self::LF => "\n",
        }
    }
}

impl FromStr for LineEnding {
    type Err = UnsupportedLineEnding;

    #[inline]
    fn from_str(s: &str) -> Result<LineEnding, UnsupportedLineEnding> {
        match s {
            "\u{000D}\u{000A}" => Ok(LineEnding::CRLF),
            "\u{000A}" => Ok(LineEnding::LF),
            _ => Err(UnsupportedLineEnding),
        }
    }
}

/// An iterator over the lines of a string, as tuples of string slice
/// and [`LineEnding`] value; it only emits non-empty lines (i.e. having
/// some content before the terminating `\r\n` or `\n`).
///
/// This struct is used internally by the library.
#[derive(Debug, Clone, Copy)]
pub(crate) struct NonEmptyLines<'a>(pub &'a str);

impl<'a> Iterator for NonEmptyLines<'a> {
    type Item = (&'a str, Option<LineEnding>);

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(lf) = self.0.find('\n') {
            if lf == 0 || (lf == 1 && self.0.as_bytes()[lf - 1] == b'\r') {
                self.0 = &self.0[(lf + 1)..];
                continue;
            }
            let trimmed = match self.0.as_bytes()[lf - 1] {
                b'\r' => (&self.0[..(lf - 1)], Some(LineEnding::CRLF)),
                _ => (&self.0[..lf], Some(LineEnding::LF)),
            };
            self.0 = &self.0[(lf + 1)..];
            return Some(trimmed);
        }
        if self.0.len() > 0 {
            let result = Some((self.0, None));
            self.0 = "";
            return result;
        } else {
            return None;
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::line_ending::NonEmptyLines;
    use crate::LineEnding;

    #[test]
    fn non_empty_lines_full_case() {
        assert_eq!(
            NonEmptyLines("LF\nCRLF\r\n\r\n\nunterminated")
                .collect::<Vec<(&str, Option<LineEnding>)>>(),
            vec![
                ("LF", Some(LineEnding::LF)),
                ("CRLF", Some(LineEnding::CRLF)),
                ("unterminated", None),
            ]
        );
    }

    #[test]
    fn non_empty_lines_new_lines_only() {
        assert_eq!(NonEmptyLines("\r\n\n\n\r\n").next(), None);
    }

    #[test]
    fn non_empty_lines_no_input() {
        assert_eq!(NonEmptyLines("").next(), None);
    }
}
<|endoftext|>


<commit_before>use nalgebra::Point3;
use num::Float;
use num::traits::FloatConst;
use std::cmp;
use std::iter::Peekable;
use std::ops::Range;
use std::marker::PhantomData;

use super::generate::{Conjoint, Indexed};
use super::primitive::{Polygon, Triangle, Quad};

pub struct UVSphere<T>
    where T: Float + FloatConst
{
    nu: usize,
    nv: usize,
    us: Range<usize>, // meridians
    vs: Peekable<Range<usize>>, // parallels
    phantom_t: PhantomData<T>,
}

impl<T> UVSphere<T>
    where T: Float + FloatConst
{
    pub fn with_unit_radius(nu: usize, nv: usize) -> Self {
        let nu = cmp::max(3, nu);
        let nv = cmp::max(3, nv);
        UVSphere {
            nu: nu,
            nv: nv,
            us: 0..nu,
            vs: (0..nv).peekable(),
            phantom_t: PhantomData,
        }
    }

    fn point(&self, u: usize, v: usize) -> Point3<T> {
        point(u, v, self.nu, self.nv)
    }

    fn indexed_point(&self, u: usize, v: usize) -> usize {
        if v == 0 {
            0
        }
        else if v == self.nv {
            ((self.nv - 1) * self.nu) + 1
        }
        else {
            ((v - 1) * self.nu) + (u % self.nu) + 1
        }
    }
}

impl<T> Conjoint<Point3<T>> for UVSphere<T>
    where T: Float + FloatConst
{
    fn conjoint_point(&self, index: usize) -> Point3<T> {
        if index == 0 {
            self.point(0, 0)
        }
        else if index == self.conjoint_point_count() - 1 {
            self.point(0, self.nv)
        }
        else {
            let index = index - 1;
            self.point(index % self.nu, (index / self.nv) + 1)
        }
    }

    fn conjoint_point_count(&self) -> usize {
        (self.nv - 1) * self.nu + 2
    }
}

impl<T> Indexed<Polygon<usize>> for UVSphere<T>
    where T: Float + FloatConst
{
    fn indexed_polygon(&self, index: usize) -> Polygon<usize> {
        let u = index % self.nu;
        let v = index / self.nu;

        let lower = self.indexed_point(u, v);
        let upper = self.indexed_point(u + 1, v + 1);
        if v == 0 {
            Polygon::Triangle(Triangle::new(lower, self.indexed_point(u, v + 1), upper))
        }
        else if v == self.nv - 1 {
            Polygon::Triangle(Triangle::new(upper, self.indexed_point(u + 1, v), lower))
        }
        else {
            Polygon::Quad(Quad::new(lower,
                                    self.indexed_point(u, v + 1),
                                    upper,
                                    self.indexed_point(u + 1, v)))
        }
    }

    fn indexed_polygon_count(&self) -> usize {
        self.nu * self.nv
    }
}

impl<T> Iterator for UVSphere<T>
    where T: Float + FloatConst
{
    type Item = Polygon<Point3<T>>;

    fn next(&mut self) -> Option<Self::Item> {
        let nu = self.nu;
        let nv = self.nv;

        // Iterate over meridians (`self.us`). When meridians are exhausted,
        // reset the iteration and advance iteration over parallels (`self.vs`).
        // Continue until parallels are exhausted.
        let u = match self.us.next() {
            Some(u) => u,
            None => {
                self.vs.next();
                self.us = 1..nu;
                0
            },
        };
        self.vs.peek().map(|v| {
            let v = *v;

            // Generate the points at the current meridian and parallel. The
            // upper and lower bounds of (u, v) are always used, so Generate
            // them in advance. Emit triangles at the poles, otherwise quads.
            let lower = point(u, v, nu, nv);
            let upper = point(u + 1, v + 1, nu, nv);
            if v == 0 {
                Polygon::Triangle(Triangle::new(lower, point(u, v + 1, nu, nv), upper))
            }
            else if v == nv - 1 {
                Polygon::Triangle(Triangle::new(upper, point(u + 1, v, nu, nv), lower))
            }
            else {
                Polygon::Quad(Quad::new(lower,
                                        point(u, v + 1, nu, nv),
                                        upper,
                                        point(u + 1, v, nu, nv)))
            }
        })
    }
}

fn point<T>(u: usize, v: usize, nu: usize, nv: usize) -> Point3<T>
    where T: Float + FloatConst
{
    let u = (T::from(u).unwrap() / T::from(nu).unwrap()) * T::PI() * (T::one() + T::one());
    let v = (T::from(v).unwrap() / T::from(nv).unwrap()) * T::PI();
    Point3::new(u.cos() * v.sin(), u.sin() * v.sin(), v.cos())
}
<commit_msg>Use consistent names with `cube` module.<commit_after>use nalgebra::Point3;
use num::Float;
use num::traits::FloatConst;
use std::cmp;
use std::iter::Peekable;
use std::ops::Range;
use std::marker::PhantomData;

use super::generate::{Conjoint, Indexed};
use super::primitive::{Polygon, Triangle, Quad};

pub struct UVSphere<T>
    where T: Float + FloatConst
{
    nu: usize,
    nv: usize,
    us: Range<usize>, // Meridians.
    vs: Peekable<Range<usize>>, // Parallels.
    phantom_t: PhantomData<T>,
}

impl<T> UVSphere<T>
    where T: Float + FloatConst
{
    pub fn with_unit_radius(nu: usize, nv: usize) -> Self {
        let nu = cmp::max(3, nu);
        let nv = cmp::max(3, nv);
        UVSphere {
            nu: nu,
            nv: nv,
            us: 0..nu,
            vs: (0..nv).peekable(),
            phantom_t: PhantomData,
        }
    }

    fn point(&self, u: usize, v: usize) -> Point3<T> {
        point(u, v, self.nu, self.nv)
    }

    fn indexed_point(&self, u: usize, v: usize) -> usize {
        if v == 0 {
            0
        }
        else if v == self.nv {
            ((self.nv - 1) * self.nu) + 1
        }
        else {
            ((v - 1) * self.nu) + (u % self.nu) + 1
        }
    }
}

impl<T> Conjoint<Point3<T>> for UVSphere<T>
    where T: Float + FloatConst
{
    fn conjoint_point(&self, index: usize) -> Point3<T> {
        if index == 0 {
            self.point(0, 0)
        }
        else if index == self.conjoint_point_count() - 1 {
            self.point(0, self.nv)
        }
        else {
            let index = index - 1;
            self.point(index % self.nu, (index / self.nv) + 1)
        }
    }

    fn conjoint_point_count(&self) -> usize {
        (self.nv - 1) * self.nu + 2
    }
}

impl<T> Indexed<Polygon<usize>> for UVSphere<T>
    where T: Float + FloatConst
{
    fn indexed_polygon(&self, index: usize) -> Polygon<usize> {
        let u = index % self.nu;
        let v = index / self.nu;

        let low = self.indexed_point(u, v);
        let high = self.indexed_point(u + 1, v + 1);
        if v == 0 {
            Polygon::Triangle(Triangle::new(low, self.indexed_point(u, v + 1), high))
        }
        else if v == self.nv - 1 {
            Polygon::Triangle(Triangle::new(high, self.indexed_point(u + 1, v), low))
        }
        else {
            Polygon::Quad(Quad::new(low,
                                    self.indexed_point(u, v + 1),
                                    high,
                                    self.indexed_point(u + 1, v)))
        }
    }

    fn indexed_polygon_count(&self) -> usize {
        self.nu * self.nv
    }
}

impl<T> Iterator for UVSphere<T>
    where T: Float + FloatConst
{
    type Item = Polygon<Point3<T>>;

    fn next(&mut self) -> Option<Self::Item> {
        let nu = self.nu;
        let nv = self.nv;

        // Iterate over meridians (`self.us`). When meridians are exhausted,
        // reset the iteration and advance iteration over parallels (`self.vs`).
        // Continue until parallels are exhausted.
        let u = match self.us.next() {
            Some(u) => u,
            None => {
                self.vs.next();
                self.us = 1..nu;
                0
            }
        };
        self.vs.peek().map(|v| {
            let v = *v;

            // Generate the points at the current meridian and parallel. The
            // upper and lower bounds of (u, v) are always used, so generate
            // them in advance (`low` and `high`). Emit triangles at the poles,
            // otherwise quads.
            let low = point(u, v, nu, nv);
            let high = point(u + 1, v + 1, nu, nv);
            if v == 0 {
                Polygon::Triangle(Triangle::new(low, point(u, v + 1, nu, nv), high))
            }
            else if v == nv - 1 {
                Polygon::Triangle(Triangle::new(high, point(u + 1, v, nu, nv), low))
            }
            else {
                Polygon::Quad(Quad::new(low,
                                        point(u, v + 1, nu, nv),
                                        high,
                                        point(u + 1, v, nu, nv)))
            }
        })
    }
}

fn point<T>(u: usize, v: usize, nu: usize, nv: usize) -> Point3<T>
    where T: Float + FloatConst
{
    let u = (T::from(u).unwrap() / T::from(nu).unwrap()) * T::PI() * (T::one() + T::one());
    let v = (T::from(v).unwrap() / T::from(nv).unwrap()) * T::PI();
    Point3::new(u.cos() * v.sin(), u.sin() * v.sin(), v.cos())
}
<|endoftext|>