<commit_before>use bifrost::conshash::{CHError, ConsistentHashing};
use bifrost::raft;
use bifrost::raft::client::{ClientError, RaftClient};
use bifrost::raft::state_machine::callback::server::NotifyError;
use bifrost::raft::state_machine::master::ExecError;
use bifrost::rpc::{RPCError, Server as RPCServer, DEFAULT_CLIENT_POOL};
use std::cell::Cell as StdCell;
use std::io;
use std::sync::Arc;

use ram::cell::{Cell, CellHeader, ReadError, WriteError};
use ram::schema::sm as schema_sm;
use ram::schema::sm::client::SMClient as SchemaClient;
use ram::schema::Schema;
use ram::types::Id;
use server::{cell_rpc as plain_server, transactions as txn_server, CONS_HASH_ID};

use futures::prelude::{async, await};
use futures::Future;

use self::transaction::*;

static TRANSACTION_MAX_RETRY: u32 = 500;

pub mod transaction;

#[derive(Debug)]
pub enum NebClientError {
    RaftClientError(ClientError),
    ConsistentHashtableError(CHError),
}

struct AsyncClientInner {
    pub conshash: Arc<ConsistentHashing>,
    pub raft_client: Arc<RaftClient>,
    pub schema_client: SchemaClient,
}

impl AsyncClientInner {
    pub fn new<'a>(
        subscription_server: &Arc<RPCServer>,
        meta_servers: &Vec<String>,
        group: &'a str,
    ) -> Result<AsyncClientInner, NebClientError> {
        match RaftClient::new(meta_servers, raft::DEFAULT_SERVICE_ID) {
            Ok(raft_client) => {
                RaftClient::prepare_subscription(subscription_server);
                assert!(RaftClient::can_callback());
                match ConsistentHashing::new_client_with_id(CONS_HASH_ID, group, &raft_client) {
                    Ok(chash) => Ok(AsyncClientInner {
                        conshash: chash,
                        raft_client: raft_client.clone(),
                        schema_client: SchemaClient::new(
                            schema_sm::generate_sm_id(group),
                            &raft_client,
                        ),
                    }),
                    Err(err) => Err(NebClientError::ConsistentHashtableError(err)),
                }
            }
            Err(err) => Err(NebClientError::RaftClientError(err)),
        }
    }
    pub fn locate_server_id(&self, id: &Id) -> Result<u64, RPCError> {
        match self.conshash.get_server_id(id.higher) {
            Some(n) => Ok(n),
            None => Err(RPCError::IOError(io::Error::new(
                io::ErrorKind::NotFound,
                format!("cannot locate server for id {:?}", id),
            ))),
        }
    }

    pub fn locate_plain_server(
        this: Arc<Self>,
        id: Id,
    ) -> impl Future<Item = Arc<plain_server::AsyncServiceClient>, Error = RPCError> {
        let server_id = this.locate_server_id(&id).unwrap();
        DEFAULT_CLIENT_POOL
            .get_by_id_async(server_id, move |sid| this.conshash.to_server_name(sid))
            .map_err(|e| RPCError::IOError(e))
            .map(move |c| {
                plain_server::AsyncServiceClient::new(plain_server::DEFAULT_SERVICE_ID, &c)
            })
    }
    #[async]
    pub fn read_cell(this: Arc<Self>, id: Id) -> Result<Result<Cell, ReadError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, id))?;
        await!(client.read_cell(id))
    }
    #[async]
    pub fn write_cell(
        this: Arc<Self>,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, cell.id()))?;
        await!(client.write_cell(cell))
    }
    #[async]
    pub fn update_cell(
        this: Arc<Self>,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, cell.id()))?;
        await!(client.update_cell(cell))
    }
    #[async]
    pub fn upsert_cell(
        this: Arc<Self>,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, cell.id()))?;
        await!(client.upsert_cell(cell))
    }
    #[async]
    pub fn remove_cell(this: Arc<Self>, id: Id) -> Result<Result<(), WriteError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, id))?;
        await!(client.remove_cell(id))
    }
    #[async]
    pub fn transaction<TFN, TR>(this: Arc<Self>, func: TFN) -> Result<TR, TxnError>
    where
        TFN: Fn(&Transaction) -> Result<TR, TxnError>,
        TR: 'static,
        TFN: 'static,
    {
        let server_name = match this.conshash.rand_server() {
            Some(name) => name,
            None => return Err(TxnError::CannotFindAServer),
        };
        let txn_client = match txn_server::new_async_client(&server_name) {
            Ok(client) => client,
            Err(e) => return Err(TxnError::IoError(e)),
        };
        let mut txn_id: txn_server::TxnId;
        let mut retried = 0;
        while retried < TRANSACTION_MAX_RETRY {
            txn_id = match await!(txn_client.begin()) {
                Ok(Ok(id)) => id,
                _ => return Err(TxnError::CannotBegin),
            };
            let txn = Transaction {
                tid: txn_id,
                state: StdCell::new(txn_server::TxnState::Started),
                client: txn_client.clone(),
            };
            let exec_result = func(&txn);
            let mut exec_value = None;
            let mut txn_result = Ok(());
            match exec_result {
                Ok(val) => {
                    if txn.state.get() == txn_server::TxnState::Started {
                        txn_result = txn.prepare();
                        debug!("PREPARE STATE: {:?}", txn_result);
                    }
                    if txn_result.is_ok() && txn.state.get() == txn_server::TxnState::Prepared {
                        txn_result = txn.commit();
                        debug!("COMMIT STATE: {:?}", txn_result);
                    }
                    exec_value = Some(val);
                }
                Err(e) => txn_result = Err(e),
            }
            debug!("TXN CONCLUSION: {:?}", txn_result);
            match txn_result {
                Ok(()) => {
                    return Ok(exec_value.unwrap());
                }
                Err(TxnError::NotRealizable) => {
                    let abort_result = txn.abort(); // continue the loop to retry
                    debug!("TXN NOT REALIZABLE, ABORT: {:?}", abort_result);
                }
                Err(e) => {
                    // abort will always be an error to achieve early break
                    let abort_result = txn.abort();
                    debug!("TXN ERROR, ABORT: {:?}", abort_result);
                    return Err(e);
                }
            }
            retried += 1;
            debug!("Client retry transaction, {:?} times", retried);
        }
        Err(TxnError::TooManyRetry)
    }
    #[async]
    pub fn new_schema_with_id(
        this: Arc<Self>,
        schema: Schema,
    ) -> Result<Result<(), NotifyError>, ExecError> {
        await!(this.schema_client.new_schema(&schema))
    }
    #[async]
    pub fn new_schema(
        this: Arc<Self>,
        mut schema: Schema,
    ) -> Result<(u32, Option<NotifyError>), ExecError> {
        let schema_id = await!(this.schema_client.next_id())?.unwrap();
        schema.id = schema_id;
        await!(Self::new_schema_with_id(this, schema)).map(|r| {
            let error = match r {
                Ok(_) => None,
                Err(e) => Some(e),
            };
            (schema_id, error)
        })
    }
    #[async]
    pub fn del_schema(this: Arc<Self>, name: String) -> Result<Result<(), NotifyError>, ExecError> {
        await!(this.schema_client.del_schema(&name))
    }
    #[async]
    pub fn get_all_schema(this: Arc<Self>) -> Result<Vec<Schema>, ExecError> {
        Ok(await!(this.schema_client.get_all())?.unwrap())
    }
}

pub struct AsyncClient {
    inner: Arc<AsyncClientInner>,
}

impl AsyncClient {
    pub fn new<'a>(
        subscription_server: &Arc<RPCServer>,
        meta_servers: &Vec<String>,
        group: &'a str,
    ) -> Result<AsyncClient, NebClientError> {
        AsyncClientInner::new(subscription_server, meta_servers, group).map(|inner| AsyncClient {
            inner: Arc::new(inner),
        })
    }

    pub fn locate_server_id(&self, id: &Id) -> Result<u64, RPCError> {
        self.inner.locate_server_id(id)
    }

    pub fn locate_plain_server(
        &self,
        id: Id,
    ) -> impl Future<Item = Arc<plain_server::AsyncServiceClient>, Error = RPCError> {
        AsyncClientInner::locate_plain_server(self.inner.clone(), id)
    }

    pub fn read_cell(
        &self,
        id: Id,
    ) -> impl Future<Item = Result<Cell, ReadError>, Error = RPCError> {
        AsyncClientInner::read_cell(self.inner.clone(), id)
    }

    pub fn write_cell(
        &self,
        cell: Cell,
    ) -> impl Future<Item = Result<CellHeader, WriteError>, Error = RPCError> {
        AsyncClientInner::write_cell(self.inner.clone(), cell)
    }

    pub fn update_cell(
        &self,
        cell: Cell,
    ) -> impl Future<Item = Result<CellHeader, WriteError>, Error = RPCError> {
        AsyncClientInner::update_cell(self.inner.clone(), cell)
    }

    pub fn upsert_cell(
        &self,
        cell: Cell,
    ) -> impl Future<Item = Result<CellHeader, WriteError>, Error = RPCError> {
        AsyncClientInner::upsert_cell(self.inner.clone(), cell)
    }

    pub fn remove_cell(
        &self,
        id: Id,
    ) -> impl Future<Item = Result<(), WriteError>, Error = RPCError> {
        AsyncClientInner::remove_cell(self.inner.clone(), id)
    }

    pub fn transaction<TFN, TR>(&self, func: TFN) -> impl Future<Item = TR, Error = TxnError>
    where
        TFN: Fn(&Transaction) -> Result<TR, TxnError>,
        TR: 'static,
        TFN: 'static,
    {
        AsyncClientInner::transaction(self.inner.clone(), func)
    }
    pub fn new_schema_with_id(
        &self,
        schema: Schema,
    ) -> impl Future<Item = Result<(), NotifyError>, Error = ExecError> {
        AsyncClientInner::new_schema_with_id(self.inner.clone(), schema)
    }
    pub fn new_schema(
        &self,
        schema: Schema,
    ) -> impl Future<Item = (u32, Option<NotifyError>), Error = ExecError> {
        AsyncClientInner::new_schema(self.inner.clone(), schema)
    }
    pub fn del_schema(
        &self,
        name: String,
    ) -> impl Future<Item = Result<(), NotifyError>, Error = ExecError> {
        AsyncClientInner::del_schema(self.inner.clone(), name)
    }
    pub fn get_all_schema(&self) -> impl Future<Item = Vec<Schema>, Error = ExecError> {
        AsyncClientInner::get_all_schema(self.inner.clone())
    }

    pub fn raft_client(&self) -> Arc<RaftClient> {
        self.inner.raft_client.clone()
    }
}
<commit_msg>increase txn max retry to 1k, need to find a way to decrease it<commit_after>use bifrost::conshash::{CHError, ConsistentHashing};
use bifrost::raft;
use bifrost::raft::client::{ClientError, RaftClient};
use bifrost::raft::state_machine::callback::server::NotifyError;
use bifrost::raft::state_machine::master::ExecError;
use bifrost::rpc::{RPCError, Server as RPCServer, DEFAULT_CLIENT_POOL};
use std::cell::Cell as StdCell;
use std::io;
use std::sync::Arc;

use ram::cell::{Cell, CellHeader, ReadError, WriteError};
use ram::schema::sm as schema_sm;
use ram::schema::sm::client::SMClient as SchemaClient;
use ram::schema::Schema;
use ram::types::Id;
use server::{cell_rpc as plain_server, transactions as txn_server, CONS_HASH_ID};

use futures::prelude::{async, await};
use futures::Future;

use self::transaction::*;

static TRANSACTION_MAX_RETRY: u32 = 1000;

pub mod transaction;

#[derive(Debug)]
pub enum NebClientError {
    RaftClientError(ClientError),
    ConsistentHashtableError(CHError),
}

struct AsyncClientInner {
    pub conshash: Arc<ConsistentHashing>,
    pub raft_client: Arc<RaftClient>,
    pub schema_client: SchemaClient,
}

impl AsyncClientInner {
    pub fn new<'a>(
        subscription_server: &Arc<RPCServer>,
        meta_servers: &Vec<String>,
        group: &'a str,
    ) -> Result<AsyncClientInner, NebClientError> {
        match RaftClient::new(meta_servers, raft::DEFAULT_SERVICE_ID) {
            Ok(raft_client) => {
                RaftClient::prepare_subscription(subscription_server);
                assert!(RaftClient::can_callback());
                match ConsistentHashing::new_client_with_id(CONS_HASH_ID, group, &raft_client) {
                    Ok(chash) => Ok(AsyncClientInner {
                        conshash: chash,
                        raft_client: raft_client.clone(),
                        schema_client: SchemaClient::new(
                            schema_sm::generate_sm_id(group),
                            &raft_client,
                        ),
                    }),
                    Err(err) => Err(NebClientError::ConsistentHashtableError(err)),
                }
            }
            Err(err) => Err(NebClientError::RaftClientError(err)),
        }
    }
    pub fn locate_server_id(&self, id: &Id) -> Result<u64, RPCError> {
        match self.conshash.get_server_id(id.higher) {
            Some(n) => Ok(n),
            None => Err(RPCError::IOError(io::Error::new(
                io::ErrorKind::NotFound,
                format!("cannot locate server for id {:?}", id),
            ))),
        }
    }

    pub fn locate_plain_server(
        this: Arc<Self>,
        id: Id,
    ) -> impl Future<Item = Arc<plain_server::AsyncServiceClient>, Error = RPCError> {
        let server_id = this.locate_server_id(&id).unwrap();
        DEFAULT_CLIENT_POOL
            .get_by_id_async(server_id, move |sid| this.conshash.to_server_name(sid))
            .map_err(|e| RPCError::IOError(e))
            .map(move |c| {
                plain_server::AsyncServiceClient::new(plain_server::DEFAULT_SERVICE_ID, &c)
            })
    }
    #[async]
    pub fn read_cell(this: Arc<Self>, id: Id) -> Result<Result<Cell, ReadError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, id))?;
        await!(client.read_cell(id))
    }
    #[async]
    pub fn write_cell(
        this: Arc<Self>,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, cell.id()))?;
        await!(client.write_cell(cell))
    }
    #[async]
    pub fn update_cell(
        this: Arc<Self>,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, cell.id()))?;
        await!(client.update_cell(cell))
    }
    #[async]
    pub fn upsert_cell(
        this: Arc<Self>,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, cell.id()))?;
        await!(client.upsert_cell(cell))
    }
    #[async]
    pub fn remove_cell(this: Arc<Self>, id: Id) -> Result<Result<(), WriteError>, RPCError> {
        let client = await!(Self::locate_plain_server(this, id))?;
        await!(client.remove_cell(id))
    }
    #[async]
    pub fn transaction<TFN, TR>(this: Arc<Self>, func: TFN) -> Result<TR, TxnError>
    where
        TFN: Fn(&Transaction) -> Result<TR, TxnError>,
        TR: 'static,
        TFN: 'static,
    {
        let server_name = match this.conshash.rand_server() {
            Some(name) => name,
            None => return Err(TxnError::CannotFindAServer),
        };
        let txn_client = match txn_server::new_async_client(&server_name) {
            Ok(client) => client,
            Err(e) => return Err(TxnError::IoError(e)),
        };
        let mut txn_id: txn_server::TxnId;
        let mut retried = 0;
        while retried < TRANSACTION_MAX_RETRY {
            txn_id = match await!(txn_client.begin()) {
                Ok(Ok(id)) => id,
                _ => return Err(TxnError::CannotBegin),
            };
            let txn = Transaction {
                tid: txn_id,
                state: StdCell::new(txn_server::TxnState::Started),
                client: txn_client.clone(),
            };
            let exec_result = func(&txn);
            let mut exec_value = None;
            let mut txn_result = Ok(());
            match exec_result {
                Ok(val) => {
                    if txn.state.get() == txn_server::TxnState::Started {
                        txn_result = txn.prepare();
                        debug!("PREPARE STATE: {:?}", txn_result);
                    }
                    if txn_result.is_ok() && txn.state.get() == txn_server::TxnState::Prepared {
                        txn_result = txn.commit();
                        debug!("COMMIT STATE: {:?}", txn_result);
                    }
                    exec_value = Some(val);
                }
                Err(e) => txn_result = Err(e),
            }
            debug!("TXN CONCLUSION: {:?}", txn_result);
            match txn_result {
                Ok(()) => {
                    return Ok(exec_value.unwrap());
                }
                Err(TxnError::NotRealizable) => {
                    let abort_result = txn.abort(); // continue the loop to retry
                    debug!("TXN NOT REALIZABLE, ABORT: {:?}", abort_result);
                }
                Err(e) => {
                    // abort will always be an error to achieve early break
                    let abort_result = txn.abort();
                    debug!("TXN ERROR, ABORT: {:?}", abort_result);
                    return Err(e);
                }
            }
            retried += 1;
            debug!("Client retry transaction, {:?} times", retried);
        }
        Err(TxnError::TooManyRetry)
    }
    #[async]
    pub fn new_schema_with_id(
        this: Arc<Self>,
        schema: Schema,
    ) -> Result<Result<(), NotifyError>, ExecError> {
        await!(this.schema_client.new_schema(&schema))
    }
    #[async]
    pub fn new_schema(
        this: Arc<Self>,
        mut schema: Schema,
    ) -> Result<(u32, Option<NotifyError>), ExecError> {
        let schema_id = await!(this.schema_client.next_id())?.unwrap();
        schema.id = schema_id;
        await!(Self::new_schema_with_id(this, schema)).map(|r| {
            let error = match r {
                Ok(_) => None,
                Err(e) => Some(e),
            };
            (schema_id, error)
        })
    }
    #[async]
    pub fn del_schema(this: Arc<Self>, name: String) -> Result<Result<(), NotifyError>, ExecError> {
        await!(this.schema_client.del_schema(&name))
    }
    #[async]
    pub fn get_all_schema(this: Arc<Self>) -> Result<Vec<Schema>, ExecError> {
        Ok(await!(this.schema_client.get_all())?.unwrap())
    }
}

pub struct AsyncClient {
    inner: Arc<AsyncClientInner>,
}

impl AsyncClient {
    pub fn new<'a>(
        subscription_server: &Arc<RPCServer>,
        meta_servers: &Vec<String>,
        group: &'a str,
    ) -> Result<AsyncClient, NebClientError> {
        AsyncClientInner::new(subscription_server, meta_servers, group).map(|inner| AsyncClient {
            inner: Arc::new(inner),
        })
    }

    pub fn locate_server_id(&self, id: &Id) -> Result<u64, RPCError> {
        self.inner.locate_server_id(id)
    }

    pub fn locate_plain_server(
        &self,
        id: Id,
    ) -> impl Future<Item = Arc<plain_server::AsyncServiceClient>, Error = RPCError> {
        AsyncClientInner::locate_plain_server(self.inner.clone(), id)
    }

    pub fn read_cell(
        &self,
        id: Id,
    ) -> impl Future<Item = Result<Cell, ReadError>, Error = RPCError> {
        AsyncClientInner::read_cell(self.inner.clone(), id)
    }

    pub fn write_cell(
        &self,
        cell: Cell,
    ) -> impl Future<Item = Result<CellHeader, WriteError>, Error = RPCError> {
        AsyncClientInner::write_cell(self.inner.clone(), cell)
    }

    pub fn update_cell(
        &self,
        cell: Cell,
    ) -> impl Future<Item = Result<CellHeader, WriteError>, Error = RPCError> {
        AsyncClientInner::update_cell(self.inner.clone(), cell)
    }

    pub fn upsert_cell(
        &self,
        cell: Cell,
    ) -> impl Future<Item = Result<CellHeader, WriteError>, Error = RPCError> {
        AsyncClientInner::upsert_cell(self.inner.clone(), cell)
    }

    pub fn remove_cell(
        &self,
        id: Id,
    ) -> impl Future<Item = Result<(), WriteError>, Error = RPCError> {
        AsyncClientInner::remove_cell(self.inner.clone(), id)
    }

    pub fn transaction<TFN, TR>(&self, func: TFN) -> impl Future<Item = TR, Error = TxnError>
    where
        TFN: Fn(&Transaction) -> Result<TR, TxnError>,
        TR: 'static,
        TFN: 'static,
    {
        AsyncClientInner::transaction(self.inner.clone(), func)
    }
    pub fn new_schema_with_id(
        &self,
        schema: Schema,
    ) -> impl Future<Item = Result<(), NotifyError>, Error = ExecError> {
        AsyncClientInner::new_schema_with_id(self.inner.clone(), schema)
    }
    pub fn new_schema(
        &self,
        schema: Schema,
    ) -> impl Future<Item = (u32, Option<NotifyError>), Error = ExecError> {
        AsyncClientInner::new_schema(self.inner.clone(), schema)
    }
    pub fn del_schema(
        &self,
        name: String,
    ) -> impl Future<Item = Result<(), NotifyError>, Error = ExecError> {
        AsyncClientInner::del_schema(self.inner.clone(), name)
    }
    pub fn get_all_schema(&self) -> impl Future<Item = Vec<Schema>, Error = ExecError> {
        AsyncClientInner::get_all_schema(self.inner.clone())
    }

    pub fn raft_client(&self) -> Arc<RaftClient> {
        self.inner.raft_client.clone()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

// #[no_mangle]
// pub extern "C" fn some_new_fn() -> c_int {
//     println!("some_new_fn");
//     65 as c_int
// }

#[no_mangle]
pub extern "C" fn start(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    println!("Rust - start()");

    // println!("start");
    // 88 as c_int

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    println!("Rust - address: {}", host_address);

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    let kill_tx = k_tx.clone();
    let mut k_tx_ptr = Box::new(k_tx);
    unsafe {
        register_stop_tx(&mut *k_tx_ptr);
    }

    // Writer thread's channel
    let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    let mut w_tx_ptr = Box::new(w_tx);
    unsafe {
        register_writer_tx(&mut *w_tx_ptr);
    }

    println!("Attempting connect to: {}", host_address);

    // let result = TcpStream::connect(host_address);
    // if result.is_err() {
    //     println!("Error connecting to {} - {}", host_address, result.unwrap_err());
    //     return -1 as c_int;
    // }
    // println!("Connected");
    // on_connect_handler();
    //
    // let stream = result.unwrap();
    // let client = Bstream::new(stream);
    //
    // let r_client = client.clone();
    // let r_kill_tx = kill_tx.clone();
    //
    // let w_client = client.clone();
    // let w_kill_tx = kill_tx.clone();
    //
    // // Start the reader thread
    // thread::Builder::new()
    //     .name("ReaderThread".to_string())
    //     .spawn(move||{
    //         reader_thread(r_client, handler, r_kill_tx)
    //     }).unwrap();
    //
    // // Start the writer thread
    // thread::Builder::new()
    //     .name("WriterThread".to_string())
    //     .spawn(move||{
    //         writer_thread(w_rx, w_client, w_kill_tx)
    //     }).unwrap();
    //
    // // Wait for the kill signal
    // match kill_rx.recv() {
    //     Ok(_) => { }
    //     Err(e) => {
    //         println!("Error on kill channel: {}", e);
    //         return -1 as c_int;
    //     }
    // };
    // on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

// /// Connects to the provided address, (eg "123.123.123.123:3000") and registers
// /// the on data received handler
// #[no_mangle]
// pub extern "C" fn connect(address: *const c_char,
//     handler: extern fn(*const c_char, c_int),
//     on_connect_handler: extern fn(),
//     on_disconnect_handler: extern fn()) -> c_int {
//
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//
//
//     78 as c_int
//
//
//     let mut r_address;
//     unsafe {
//         r_address = CStr::from_ptr(address);
//     }
//     let s_address = r_address.to_bytes();
//     let host_address = match str::from_utf8(s_address) {
//         Ok(safe_str) => safe_str,
//         Err(_) => {
//             println!("Invalid host address");
//             return -1 as c_int;
//         }
//     };
//
//     // Create and register a way to kill this client
//     let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
//     let kill_tx = k_tx.clone();
//     let mut k_tx_ptr = Box::new(k_tx);
//     unsafe {
//         register_stop_tx(&mut *k_tx_ptr);
//     }
//
//     // Writer thread's channel
//     let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
//     let mut w_tx_ptr = Box::new(w_tx);
//     unsafe {
//         register_writer_tx(&mut *w_tx_ptr);
//     }
//
//     println!("Attempting connect to: {}", host_address);
//
//     let result = TcpStream::connect(host_address);
//     if result.is_err() {
//         println!("Error connecting to {} - {}", host_address, result.unwrap_err());
//         return -1 as c_int;
//     }
//     println!("Connected");
//     on_connect_handler();
//
//     let stream = result.unwrap();
//     let client = Bstream::new(stream);
//
//     let r_client = client.clone();
//     let r_kill_tx = kill_tx.clone();
//
//     let w_client = client.clone();
//     let w_kill_tx = kill_tx.clone();
//
//     // Start the reader thread
//     thread::Builder::new()
//         .name("ReaderThread".to_string())
//         .spawn(move||{
//             reader_thread(r_client, handler, r_kill_tx)
//         }).unwrap();
//
//     // Start the writer thread
//     thread::Builder::new()
//         .name("WriterThread".to_string())
//         .spawn(move||{
//             writer_thread(w_rx, w_client, w_kill_tx)
//         }).unwrap();
//
//     // Wait for the kill signal
//     match kill_rx.recv() {
//         Ok(_) => { }
//         Err(e) => {
//             println!("Error on kill channel: {}", e);
//             return -1 as c_int;
//         }
//     };
//     on_disconnect_handler();
//
//     // Exit out in standard C fashion
//     0 as c_int
// }

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<commit_msg>Debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

// #[no_mangle]
// pub extern "C" fn some_new_fn() -> c_int {
//     println!("some_new_fn");
//     65 as c_int
// }

#[no_mangle]
pub extern "C" fn start(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    println!("Rust - start()");

    // println!("start");
    // 88 as c_int

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    println!("Rust - address: {}", host_address);

    // Create and register a way to kill this client
    // let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    // let kill_tx = k_tx.clone();
    // let mut k_tx_ptr = Box::new(k_tx);
    // unsafe {
    //     register_stop_tx(&mut *k_tx_ptr);
    // }
    //
    // // Writer thread's channel
    // let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    // let mut w_tx_ptr = Box::new(w_tx);
    // unsafe {
    //     register_writer_tx(&mut *w_tx_ptr);
    // }
    //
    // println!("Attempting connect to: {}", host_address);

    // let result = TcpStream::connect(host_address);
    // if result.is_err() {
    //     println!("Error connecting to {} - {}", host_address, result.unwrap_err());
    //     return -1 as c_int;
    // }
    // println!("Connected");
    // on_connect_handler();
    //
    // let stream = result.unwrap();
    // let client = Bstream::new(stream);
    //
    // let r_client = client.clone();
    // let r_kill_tx = kill_tx.clone();
    //
    // let w_client = client.clone();
    // let w_kill_tx = kill_tx.clone();
    //
    // // Start the reader thread
    // thread::Builder::new()
    //     .name("ReaderThread".to_string())
    //     .spawn(move||{
    //         reader_thread(r_client, handler, r_kill_tx)
    //     }).unwrap();
    //
    // // Start the writer thread
    // thread::Builder::new()
    //     .name("WriterThread".to_string())
    //     .spawn(move||{
    //         writer_thread(w_rx, w_client, w_kill_tx)
    //     }).unwrap();
    //
    // // Wait for the kill signal
    // match kill_rx.recv() {
    //     Ok(_) => { }
    //     Err(e) => {
    //         println!("Error on kill channel: {}", e);
    //         return -1 as c_int;
    //     }
    // };
    // on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

// /// Connects to the provided address, (eg "123.123.123.123:3000") and registers
// /// the on data received handler
// #[no_mangle]
// pub extern "C" fn connect(address: *const c_char,
//     handler: extern fn(*const c_char, c_int),
//     on_connect_handler: extern fn(),
//     on_disconnect_handler: extern fn()) -> c_int {
//
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//
//
//     78 as c_int
//
//
//     let mut r_address;
//     unsafe {
//         r_address = CStr::from_ptr(address);
//     }
//     let s_address = r_address.to_bytes();
//     let host_address = match str::from_utf8(s_address) {
//         Ok(safe_str) => safe_str,
//         Err(_) => {
//             println!("Invalid host address");
//             return -1 as c_int;
//         }
//     };
//
//     // Create and register a way to kill this client
//     let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
//     let kill_tx = k_tx.clone();
//     let mut k_tx_ptr = Box::new(k_tx);
//     unsafe {
//         register_stop_tx(&mut *k_tx_ptr);
//     }
//
//     // Writer thread's channel
//     let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
//     let mut w_tx_ptr = Box::new(w_tx);
//     unsafe {
//         register_writer_tx(&mut *w_tx_ptr);
//     }
//
//     println!("Attempting connect to: {}", host_address);
//
//     let result = TcpStream::connect(host_address);
//     if result.is_err() {
//         println!("Error connecting to {} - {}", host_address, result.unwrap_err());
//         return -1 as c_int;
//     }
//     println!("Connected");
//     on_connect_handler();
//
//     let stream = result.unwrap();
//     let client = Bstream::new(stream);
//
//     let r_client = client.clone();
//     let r_kill_tx = kill_tx.clone();
//
//     let w_client = client.clone();
//     let w_kill_tx = kill_tx.clone();
//
//     // Start the reader thread
//     thread::Builder::new()
//         .name("ReaderThread".to_string())
//         .spawn(move||{
//             reader_thread(r_client, handler, r_kill_tx)
//         }).unwrap();
//
//     // Start the writer thread
//     thread::Builder::new()
//         .name("WriterThread".to_string())
//         .spawn(move||{
//             writer_thread(w_rx, w_client, w_kill_tx)
//         }).unwrap();
//
//     // Wait for the kill signal
//     match kill_rx.recv() {
//         Ok(_) => { }
//         Err(e) => {
//             println!("Error on kill channel: {}", e);
//             return -1 as c_int;
//         }
//     };
//     on_disconnect_handler();
//
//     // Exit out in standard C fashion
//     0 as c_int
// }

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<|endoftext|>


<commit_before>//! A slice for bytes array representing a string
//!
//! StrSlice is designed for zero-copy string operations.
//! It should be carefully used because it just contains borrowed contents.
//! StrSlice looks similar to rust's `str`, but it just handles a sequence of
//! bytes instead of unicode. In other words, it does not consider any encoding.
//! Also, it internally uses highly low-level optimization techniques like SSE 4.2.
//!
//! # Examples
//!
//! ```ignore
//! let str1 = StrSlice::new_from_str("aaaaa");
//! let str2 = StrSlice::new_from_str("aaaaa");
//! let cmp = str1 >= str2
//! ...
//! ```

use alloc::heap;
use libc::funcs::c95::string::memcmp;
use libc::types::common::c95::c_void;
use std::cmp;
use std::cmp::Ordering;
use std::fmt::{Error, Display, Formatter};
use std::mem;
use std::raw::Slice;
use std::result::Result;
use std::str;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
#[allow(raw_pointer_derive)]
pub struct StrSlice {
  ptr: *const u8,
  len: i32,
}

impl StrSlice {
  #[inline]
  pub fn new(ptr: *const u8, len: i32) -> StrSlice {
    StrSlice {
      ptr: ptr,
      len: len
    }
  }
  #[inline]
  pub fn from_str<'a>(s: &str) -> StrSlice {
    StrSlice {
      ptr: s.as_ptr(),
      len: s.len() as i32
    }
  }

  #[inline]
  pub fn set_ptr(&mut self, ptr: *const u8) {
    self.ptr = ptr;
  }

  #[inline]
  pub fn set_len(&mut self, len: i32) {
    self.len = len;
  }

  #[inline]
  pub fn as_ptr(&self) -> *const u8 {
    self.ptr
  }

  #[inline]
  pub fn len(&self) -> i32 {
    self.len
  }

  #[inline]
  pub fn as_slice<'a>(&'a self) -> &'a [u8] {
    let slice = Slice {data: self.ptr, len: (self.len as usize)};
    unsafe {
      mem::transmute(slice)
    }
  }

  #[inline]
  pub fn as_slice_mut<'a>(&'a self) -> &'a mut [u8] {
    let slice = Slice {data: self.ptr, len: (self.len as usize)};
    unsafe {
      mem::transmute(slice)
    }
  }

  #[inline]
  pub fn as_str<'a>(&'a self) -> &'a str {
    str::from_utf8(self.as_slice()).unwrap()
  }

  #[inline]
  pub fn to_string(&self) -> String {
    String::from(self.as_str())
  }
}

pub unsafe fn alloc_str_slice(len: usize, align: usize) -> StrSlice {
  StrSlice {
    ptr: heap::allocate(len, align),
    len: len as i32
  }
}

/// Deallocate the pointer contained in the StrSlice with the align size
/// After deallocation, do not use this StrSlice
pub unsafe fn dealloc_str_slice(slice: &mut StrSlice, align: usize) {
  heap::deallocate(slice.as_ptr() as *mut u8, slice.len() as usize, align);
  slice.set_ptr(0 as *mut u8);
  slice.set_len(0 as i32);
}

impl Display for StrSlice {
  fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
    Display::fmt(self.as_str(), f)
  }
}

impl PartialEq for StrSlice {
  #[inline]
  fn eq(&self, other: &StrSlice) -> bool {
    self.len() == other.len() && rawcmp(self.ptr, other.ptr, self.len) == 0
  }

  #[inline]
  fn ne(&self, other: &StrSlice) -> bool {
    !(self.eq(other))
  }
}

#[inline]
fn rawcmp(x: *const u8, y: *const u8, len: i32) -> i32 {
  unsafe {
    memcmp(
      x as *const c_void,
      y as *const c_void,
      len as u64
    )
  }
}

impl PartialOrd for StrSlice {
  #[inline]
  fn partial_cmp(&self, other: &StrSlice) -> Option<Ordering> {
    None
  }

  #[inline]
  fn lt(&self, other: &StrSlice) -> bool {
    let cmp = rawcmp(self.ptr, other.ptr, cmp::min(self.len, other.len));
    match cmp {
      0 => (self.len() - other.len()) < 0,
      _ => cmp < 0
    }
  }

  #[inline]
  fn le(&self, other: &StrSlice) -> bool {
    let cmp = rawcmp(self.ptr, other.ptr, cmp::min(self.len, other.len));
    match cmp {
      0 => (self.len() - other.len()) <= 0,
      _ => cmp <= 0
    }
  }

  #[inline]
  fn gt(&self, other: &StrSlice) -> bool {
    let cmp = rawcmp(self.ptr, other.ptr, cmp::min(self.len, other.len));
    match cmp {
      0 => (self.len() - other.len()) > 0,
      _ => cmp > 0
    }
  }

  #[inline]
  fn ge(&self, other: &StrSlice) -> bool {
    let cmp = rawcmp(self.ptr, other.ptr, cmp::min(self.len, other.len));
    match cmp {
      0 => (self.len() - other.len()) >= 0,
      _ => cmp >= 0
    }
  }
}

/// Split a slice with the delimiter into multiple slices.
/// Return tuple contains the length involved in the output slices
/// and how many slices are filled in out_slices.
#[inline]
pub unsafe fn split_str_slice(slice: &mut StrSlice,
                   out_slices: &mut [StrSlice],
                   delim: u8) -> (usize, usize) {
  let mut split_idx  : usize = 0;
  let mut last_pos   : usize = 0; // keep the start offset
  let mut cur_pos    : usize = 0; // the current offset

  let line_len = slice.len() as usize;

  while cur_pos < line_len && split_idx < out_slices.len() {
    let c: u8 = *slice.as_ptr().offset(cur_pos as isize);

    // check two cases:
    // * if the character is line delimiter
    // * if this position is the last position in this line
    if c == delim || cur_pos == (line_len - 1) {
      // set the str slice
      out_slices[split_idx].set_ptr(slice.as_ptr().offset(last_pos as isize));
      out_slices[split_idx].set_len((cur_pos - last_pos) as i32);

      // move forward the indices
      last_pos = cur_pos + 1;
      split_idx = split_idx + 1;
    }

    cur_pos = cur_pos + 1;
  }

  // 1) the splitted length 2) how many splits are found?
  (last_pos, split_idx)
}

#[test]
fn test_split_str_slice_case1() {
  // less than num of output slices
  let mut input = StrSlice::from_str("aaa,bbb,ccc,ddd,eee");
  let mut slices: [StrSlice;6] = unsafe { mem::zeroed() };
  let res = unsafe {split_str_slice(&mut input, &mut slices, ',' as u8)};
  assert_eq!(input.len() as usize, res.0);
  assert_eq!(5, res.1);
}

#[test]
fn test_split_str_slice_case2() {
  // equal to num of output slices
  let mut input = StrSlice::from_str("aaa,bbb,ccc,ddd,eee,fff");
  let mut slices: [StrSlice;6] = unsafe { mem::zeroed() };
  let res = unsafe {split_str_slice(&mut input, &mut slices, ',' as u8)};
  assert_eq!(input.len() as usize, res.0);
  assert_eq!(6, res.1);
}

#[test]
fn test_split_str_slice_case3() {
  // greater than num of output slices
  let mut input = StrSlice::from_str("aaa,bbb,ccc,ddd,eee,fff,ggg,hhh");
                                   // 0123456789012345678901234567890
  let mut slices: [StrSlice;6] = unsafe { mem::zeroed() };
  let res = unsafe {split_str_slice(&mut input, &mut slices, ',' as u8)};
  assert_eq!(24 as usize, res.0);
  assert_eq!(6, res.1);
}
<commit_msg>Updated the module name for c_void and c_int.<commit_after>//! A slice for bytes array representing a string
//!
//! StrSlice is designed for zero-copy string operations.
//! It should be carefully used because it just contains borrowed contents.
//! StrSlice looks similar to rust's `str`, but it just handles a sequence of
//! bytes instead of unicode. In other words, it does not consider any encoding.
//! Also, it internally uses highly low-level optimization techniques like SSE 4.2.
//!
//! # Examples
//!
//! ```ignore
//! let str1 = StrSlice::new_from_str("aaaaa");
//! let str2 = StrSlice::new_from_str("aaaaa");
//! let cmp = str1 >= str2
//! ...
//! ```

use alloc::heap;
use libc::{c_void, memcmp};
use std::cmp;
use std::cmp::Ordering;
use std::fmt::{Error, Display, Formatter};
use std::mem;
use std::raw::Slice;
use std::result::Result;
use std::str;

#[derive(Copy, Clone, Debug)]
#[repr(C)]
#[allow(raw_pointer_derive)]
pub struct StrSlice {
  ptr: *const u8,
  len: i32,
}

impl StrSlice {
  #[inline]
  pub fn new(ptr: *const u8, len: i32) -> StrSlice {
    StrSlice {
      ptr: ptr,
      len: len
    }
  }
  #[inline]
  pub fn from_str<'a>(s: &str) -> StrSlice {
    StrSlice {
      ptr: s.as_ptr(),
      len: s.len() as i32
    }
  }

  #[inline]
  pub fn set_ptr(&mut self, ptr: *const u8) {
    self.ptr = ptr;
  }

  #[inline]
  pub fn set_len(&mut self, len: i32) {
    self.len = len;
  }

  #[inline]
  pub fn as_ptr(&self) -> *const u8 {
    self.ptr
  }

  #[inline]
  pub fn len(&self) -> i32 {
    self.len
  }

  #[inline]
  pub fn as_slice<'a>(&'a self) -> &'a [u8] {
    let slice = Slice {data: self.ptr, len: (self.len as usize)};
    unsafe {
      mem::transmute(slice)
    }
  }

  #[inline]
  pub fn as_slice_mut<'a>(&'a self) -> &'a mut [u8] {
    let slice = Slice {data: self.ptr, len: (self.len as usize)};
    unsafe {
      mem::transmute(slice)
    }
  }

  #[inline]
  pub fn as_str<'a>(&'a self) -> &'a str {
    str::from_utf8(self.as_slice()).unwrap()
  }

  #[inline]
  pub fn to_string(&self) -> String {
    String::from(self.as_str())
  }
}

pub unsafe fn alloc_str_slice(len: usize, align: usize) -> StrSlice {
  StrSlice {
    ptr: heap::allocate(len, align),
    len: len as i32
  }
}

/// Deallocate the pointer contained in the StrSlice with the align size
/// After deallocation, do not use this StrSlice
pub unsafe fn dealloc_str_slice(slice: &mut StrSlice, align: usize) {
  heap::deallocate(slice.as_ptr() as *mut u8, slice.len() as usize, align);
  slice.set_ptr(0 as *mut u8);
  slice.set_len(0 as i32);
}

impl Display for StrSlice {
  fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
    Display::fmt(self.as_str(), f)
  }
}

impl PartialEq for StrSlice {
  #[inline]
  fn eq(&self, other: &StrSlice) -> bool {
    self.len() == other.len() && rawcmp(self.ptr, other.ptr, self.len) == 0
  }

  #[inline]
  fn ne(&self, other: &StrSlice) -> bool {
    !(self.eq(other))
  }
}

#[inline]
fn rawcmp(x: *const u8, y: *const u8, len: i32) -> i32 {
  unsafe {
    memcmp(
      x as *const c_void,
      y as *const c_void,
      len as usize
    )
  }
}

impl PartialOrd for StrSlice {
  #[inline]
  fn partial_cmp(&self, other: &StrSlice) -> Option<Ordering> {
    None
  }

  #[inline]
  fn lt(&self, other: &StrSlice) -> bool {
    let cmp = rawcmp(self.ptr, other.ptr, cmp::min(self.len, other.len));
    match cmp {
      0 => (self.len() - other.len()) < 0,
      _ => cmp < 0
    }
  }

  #[inline]
  fn le(&self, other: &StrSlice) -> bool {
    let cmp = rawcmp(self.ptr, other.ptr, cmp::min(self.len, other.len));
    match cmp {
      0 => (self.len() - other.len()) <= 0,
      _ => cmp <= 0
    }
  }

  #[inline]
  fn gt(&self, other: &StrSlice) -> bool {
    let cmp = rawcmp(self.ptr, other.ptr, cmp::min(self.len, other.len));
    match cmp {
      0 => (self.len() - other.len()) > 0,
      _ => cmp > 0
    }
  }

  #[inline]
  fn ge(&self, other: &StrSlice) -> bool {
    let cmp = rawcmp(self.ptr, other.ptr, cmp::min(self.len, other.len));
    match cmp {
      0 => (self.len() - other.len()) >= 0,
      _ => cmp >= 0
    }
  }
}

/// Split a slice with the delimiter into multiple slices.
/// Return tuple contains the length involved in the output slices
/// and how many slices are filled in out_slices.
#[inline]
pub unsafe fn split_str_slice(slice: &mut StrSlice,
                   out_slices: &mut [StrSlice],
                   delim: u8) -> (usize, usize) {
  let mut split_idx  : usize = 0;
  let mut last_pos   : usize = 0; // keep the start offset
  let mut cur_pos    : usize = 0; // the current offset

  let line_len = slice.len() as usize;

  while cur_pos < line_len && split_idx < out_slices.len() {
    let c: u8 = *slice.as_ptr().offset(cur_pos as isize);

    // check two cases:
    // * if the character is line delimiter
    // * if this position is the last position in this line
    if c == delim || cur_pos == (line_len - 1) {
      // set the str slice
      out_slices[split_idx].set_ptr(slice.as_ptr().offset(last_pos as isize));
      out_slices[split_idx].set_len((cur_pos - last_pos) as i32);

      // move forward the indices
      last_pos = cur_pos + 1;
      split_idx = split_idx + 1;
    }

    cur_pos = cur_pos + 1;
  }

  // 1) the splitted length 2) how many splits are found?
  (last_pos, split_idx)
}

#[test]
fn test_split_str_slice_case1() {
  // less than num of output slices
  let mut input = StrSlice::from_str("aaa,bbb,ccc,ddd,eee");
  let mut slices: [StrSlice;6] = unsafe { mem::zeroed() };
  let res = unsafe {split_str_slice(&mut input, &mut slices, ',' as u8)};
  assert_eq!(input.len() as usize, res.0);
  assert_eq!(5, res.1);
}

#[test]
fn test_split_str_slice_case2() {
  // equal to num of output slices
  let mut input = StrSlice::from_str("aaa,bbb,ccc,ddd,eee,fff");
  let mut slices: [StrSlice;6] = unsafe { mem::zeroed() };
  let res = unsafe {split_str_slice(&mut input, &mut slices, ',' as u8)};
  assert_eq!(input.len() as usize, res.0);
  assert_eq!(6, res.1);
}

#[test]
fn test_split_str_slice_case3() {
  // greater than num of output slices
  let mut input = StrSlice::from_str("aaa,bbb,ccc,ddd,eee,fff,ggg,hhh");
                                   // 0123456789012345678901234567890
  let mut slices: [StrSlice;6] = unsafe { mem::zeroed() };
  let res = unsafe {split_str_slice(&mut input, &mut slices, ',' as u8)};
  assert_eq!(24 as usize, res.0);
  assert_eq!(6, res.1);
}
<|endoftext|>


<commit_before>use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use std::ops::ControlFlow;

#[cfg(test)]
mod tests;

pub fn post_order_from<G: DirectedGraph + WithSuccessors + WithNumNodes>(
    graph: &G,
    start_node: G::Node,
) -> Vec<G::Node> {
    post_order_from_to(graph, start_node, None)
}

pub fn post_order_from_to<G: DirectedGraph + WithSuccessors + WithNumNodes>(
    graph: &G,
    start_node: G::Node,
    end_node: Option<G::Node>,
) -> Vec<G::Node> {
    let mut visited: IndexVec<G::Node, bool> = IndexVec::from_elem_n(false, graph.num_nodes());
    let mut result: Vec<G::Node> = Vec::with_capacity(graph.num_nodes());
    if let Some(end_node) = end_node {
        visited[end_node] = true;
    }
    post_order_walk(graph, start_node, &mut result, &mut visited);
    result
}

fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>(
    graph: &G,
    node: G::Node,
    result: &mut Vec<G::Node>,
    visited: &mut IndexVec<G::Node, bool>,
) {
    if visited[node] {
        return;
    }
    visited[node] = true;

    for successor in graph.successors(node) {
        post_order_walk(graph, successor, result, visited);
    }

    result.push(node);
}

pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>(
    graph: &G,
    start_node: G::Node,
) -> Vec<G::Node> {
    let mut vec = post_order_from(graph, start_node);
    vec.reverse();
    vec
}

/// A "depth-first search" iterator for a directed graph.
pub struct DepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    graph: &'graph G,
    stack: Vec<G::Node>,
    visited: BitSet<G::Node>,
}

impl<G> DepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    pub fn new(graph: &'graph G, start_node: G::Node) -> Self {
        Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) }
    }
}

impl<G> Iterator for DepthFirstSearch<'_, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    type Item = G::Node;

    fn next(&mut self) -> Option<G::Node> {
        let DepthFirstSearch { stack, visited, graph } = self;
        let n = stack.pop()?;
        stack.extend(graph.successors(n).filter(|&m| visited.insert(m)));
        Some(n)
    }
}

/// The status of a node in the depth-first search.
///
/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated
/// during DFS.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NodeStatus {
    /// This node has been examined by the depth-first search but is not yet `Settled`.
    ///
    /// Also referred to as "gray" or "discovered" nodes in [CLR].
    ///
    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
    Visited,

    /// This node and all nodes reachable from it have been examined by the depth-first search.
    ///
    /// Also referred to as "black" or "finished" nodes in [CLR].
    ///
    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
    Settled,
}

struct Event<N> {
    node: N,
    becomes: NodeStatus,
}

/// A depth-first search that also tracks when all successors of a node have been examined.
///
/// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby
/// referred to as **CLR**. However, we use the terminology in [`NodeStatus`] above instead of
/// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status,
/// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes
/// reachable from it have been examined. This allows us to differentiate between "tree", "back"
/// and "forward" edges (see [`TriColorVisitor::node_examined`]).
///
/// Unlike the pseudocode in [CLR], this implementation is iterative and does not use timestamps.
/// We accomplish this by storing `Event`s on the stack that result in a (possible) state change
/// for each node. A `Visited` event signifies that we should examine this node if it has not yet
/// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as
/// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of
/// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node
/// may exist on the stack simultaneously if a node has multiple predecessors, but only one
/// `Settled` event will ever be created for each node. After all `Visited` events for a node's
/// successors have been popped off the stack (as well as any new events triggered by visiting
/// those successors), we will pop off that node's `Settled` event.
///
/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
/// [`NodeStatus`]: ./enum.NodeStatus.html
/// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined
pub struct TriColorDepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    graph: &'graph G,
    stack: Vec<Event<G::Node>>,
    visited: BitSet<G::Node>,
    settled: BitSet<G::Node>,
}

impl<G> TriColorDepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    pub fn new(graph: &'graph G) -> Self {
        TriColorDepthFirstSearch {
            graph,
            stack: vec![],
            visited: BitSet::new_empty(graph.num_nodes()),
            settled: BitSet::new_empty(graph.num_nodes()),
        }
    }

    /// Performs a depth-first search, starting from the given `root`.
    ///
    /// This won't visit nodes that are not reachable from `root`.
    pub fn run_from<V>(mut self, root: G::Node, visitor: &mut V) -> Option<V::BreakVal>
    where
        V: TriColorVisitor<G>,
    {
        use NodeStatus::{Settled, Visited};

        self.stack.push(Event { node: root, becomes: Visited });

        loop {
            match self.stack.pop()? {
                Event { node, becomes: Settled } => {
                    let not_previously_settled = self.settled.insert(node);
                    assert!(not_previously_settled, "A node should be settled exactly once");
                    if let ControlFlow::Break(val) = visitor.node_settled(node) {
                        return Some(val);
                    }
                }

                Event { node, becomes: Visited } => {
                    let not_previously_visited = self.visited.insert(node);
                    let prior_status = if not_previously_visited {
                        None
                    } else if self.settled.contains(node) {
                        Some(Settled)
                    } else {
                        Some(Visited)
                    };

                    if let ControlFlow::Break(val) = visitor.node_examined(node, prior_status) {
                        return Some(val);
                    }

                    // If this node has already been examined, we are done.
                    if prior_status.is_some() {
                        continue;
                    }

                    // Otherwise, push a `Settled` event for this node onto the stack, then
                    // schedule its successors for examination.
                    self.stack.push(Event { node, becomes: Settled });
                    for succ in self.graph.successors(node) {
                        if !visitor.ignore_edge(node, succ) {
                            self.stack.push(Event { node: succ, becomes: Visited });
                        }
                    }
                }
            }
        }
    }
}

impl<G> TriColorDepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode,
{
    /// Performs a depth-first search, starting from `G::start_node()`.
    ///
    /// This won't visit nodes that are not reachable from the start node.
    pub fn run_from_start<V>(self, visitor: &mut V) -> Option<V::BreakVal>
    where
        V: TriColorVisitor<G>,
    {
        let root = self.graph.start_node();
        self.run_from(root, visitor)
    }
}

/// What to do when a node is examined or becomes `Settled` during DFS.
pub trait TriColorVisitor<G>
where
    G: ?Sized + DirectedGraph,
{
    /// The value returned by this search.
    type BreakVal;

    /// Called when a node is examined by the depth-first search.
    ///
    /// By checking the value of `prior_status`, this visitor can determine whether the edge
    /// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge
    /// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search"
    /// chapter in [CLR] or [wikipedia].
    ///
    /// If you want to know *both* nodes linked by each edge, you'll need to modify
    /// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event.
    ///
    /// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search
    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
    fn node_examined(
        &mut self,
        _node: G::Node,
        _prior_status: Option<NodeStatus>,
    ) -> ControlFlow<Self::BreakVal> {
        ControlFlow::CONTINUE
    }

    /// Called after all nodes reachable from this one have been examined.
    fn node_settled(&mut self, _node: G::Node) -> ControlFlow<Self::BreakVal> {
        ControlFlow::CONTINUE
    }

    /// Behave as if no edges exist from `source` to `target`.
    fn ignore_edge(&mut self, _source: G::Node, _target: G::Node) -> bool {
        false
    }
}

/// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists.
pub struct CycleDetector;

impl<G> TriColorVisitor<G> for CycleDetector
where
    G: ?Sized + DirectedGraph,
{
    type BreakVal = ();

    fn node_examined(
        &mut self,
        _node: G::Node,
        prior_status: Option<NodeStatus>,
    ) -> ControlFlow<Self::BreakVal> {
        match prior_status {
            Some(NodeStatus::Visited) => ControlFlow::BREAK,
            _ => ControlFlow::CONTINUE,
        }
    }
}
<commit_msg>Move post order walk to iterative approach<commit_after>use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use std::ops::ControlFlow;

#[cfg(test)]
mod tests;

pub fn post_order_from<G: DirectedGraph + WithSuccessors + WithNumNodes>(
    graph: &G,
    start_node: G::Node,
) -> Vec<G::Node> {
    post_order_from_to(graph, start_node, None)
}

pub fn post_order_from_to<G: DirectedGraph + WithSuccessors + WithNumNodes>(
    graph: &G,
    start_node: G::Node,
    end_node: Option<G::Node>,
) -> Vec<G::Node> {
    let mut visited: IndexVec<G::Node, bool> = IndexVec::from_elem_n(false, graph.num_nodes());
    let mut result: Vec<G::Node> = Vec::with_capacity(graph.num_nodes());
    if let Some(end_node) = end_node {
        visited[end_node] = true;
    }
    post_order_walk(graph, start_node, &mut result, &mut visited);
    result
}

fn post_order_walk<G: DirectedGraph + WithSuccessors + WithNumNodes>(
    graph: &G,
    node: G::Node,
    result: &mut Vec<G::Node>,
    visited: &mut IndexVec<G::Node, bool>,
) {
    struct PostOrderFrame<Node, Iter> {
        node: Node,
        iter: Iter,
    }

    if visited[node] {
        return;
    }

    let mut stack = vec![PostOrderFrame { node, iter: graph.successors(node) }];

    'recurse: while let Some(frame) = stack.last_mut() {
        let node = frame.node;
        visited[node] = true;

        while let Some(successor) = frame.iter.next() {
            if !visited[successor] {
                stack.push(PostOrderFrame { node: successor, iter: graph.successors(successor) });
                continue 'recurse;
            }
        }

        let _ = stack.pop();
        result.push(node);
    }
}

pub fn reverse_post_order<G: DirectedGraph + WithSuccessors + WithNumNodes>(
    graph: &G,
    start_node: G::Node,
) -> Vec<G::Node> {
    let mut vec = post_order_from(graph, start_node);
    vec.reverse();
    vec
}

/// A "depth-first search" iterator for a directed graph.
pub struct DepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    graph: &'graph G,
    stack: Vec<G::Node>,
    visited: BitSet<G::Node>,
}

impl<G> DepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    pub fn new(graph: &'graph G, start_node: G::Node) -> Self {
        Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) }
    }
}

impl<G> Iterator for DepthFirstSearch<'_, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    type Item = G::Node;

    fn next(&mut self) -> Option<G::Node> {
        let DepthFirstSearch { stack, visited, graph } = self;
        let n = stack.pop()?;
        stack.extend(graph.successors(n).filter(|&m| visited.insert(m)));
        Some(n)
    }
}

/// The status of a node in the depth-first search.
///
/// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated
/// during DFS.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NodeStatus {
    /// This node has been examined by the depth-first search but is not yet `Settled`.
    ///
    /// Also referred to as "gray" or "discovered" nodes in [CLR].
    ///
    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
    Visited,

    /// This node and all nodes reachable from it have been examined by the depth-first search.
    ///
    /// Also referred to as "black" or "finished" nodes in [CLR].
    ///
    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
    Settled,
}

struct Event<N> {
    node: N,
    becomes: NodeStatus,
}

/// A depth-first search that also tracks when all successors of a node have been examined.
///
/// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby
/// referred to as **CLR**. However, we use the terminology in [`NodeStatus`] above instead of
/// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status,
/// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes
/// reachable from it have been examined. This allows us to differentiate between "tree", "back"
/// and "forward" edges (see [`TriColorVisitor::node_examined`]).
///
/// Unlike the pseudocode in [CLR], this implementation is iterative and does not use timestamps.
/// We accomplish this by storing `Event`s on the stack that result in a (possible) state change
/// for each node. A `Visited` event signifies that we should examine this node if it has not yet
/// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as
/// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of
/// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node
/// may exist on the stack simultaneously if a node has multiple predecessors, but only one
/// `Settled` event will ever be created for each node. After all `Visited` events for a node's
/// successors have been popped off the stack (as well as any new events triggered by visiting
/// those successors), we will pop off that node's `Settled` event.
///
/// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
/// [`NodeStatus`]: ./enum.NodeStatus.html
/// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined
pub struct TriColorDepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    graph: &'graph G,
    stack: Vec<Event<G::Node>>,
    visited: BitSet<G::Node>,
    settled: BitSet<G::Node>,
}

impl<G> TriColorDepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
{
    pub fn new(graph: &'graph G) -> Self {
        TriColorDepthFirstSearch {
            graph,
            stack: vec![],
            visited: BitSet::new_empty(graph.num_nodes()),
            settled: BitSet::new_empty(graph.num_nodes()),
        }
    }

    /// Performs a depth-first search, starting from the given `root`.
    ///
    /// This won't visit nodes that are not reachable from `root`.
    pub fn run_from<V>(mut self, root: G::Node, visitor: &mut V) -> Option<V::BreakVal>
    where
        V: TriColorVisitor<G>,
    {
        use NodeStatus::{Settled, Visited};

        self.stack.push(Event { node: root, becomes: Visited });

        loop {
            match self.stack.pop()? {
                Event { node, becomes: Settled } => {
                    let not_previously_settled = self.settled.insert(node);
                    assert!(not_previously_settled, "A node should be settled exactly once");
                    if let ControlFlow::Break(val) = visitor.node_settled(node) {
                        return Some(val);
                    }
                }

                Event { node, becomes: Visited } => {
                    let not_previously_visited = self.visited.insert(node);
                    let prior_status = if not_previously_visited {
                        None
                    } else if self.settled.contains(node) {
                        Some(Settled)
                    } else {
                        Some(Visited)
                    };

                    if let ControlFlow::Break(val) = visitor.node_examined(node, prior_status) {
                        return Some(val);
                    }

                    // If this node has already been examined, we are done.
                    if prior_status.is_some() {
                        continue;
                    }

                    // Otherwise, push a `Settled` event for this node onto the stack, then
                    // schedule its successors for examination.
                    self.stack.push(Event { node, becomes: Settled });
                    for succ in self.graph.successors(node) {
                        if !visitor.ignore_edge(node, succ) {
                            self.stack.push(Event { node: succ, becomes: Visited });
                        }
                    }
                }
            }
        }
    }
}

impl<G> TriColorDepthFirstSearch<'graph, G>
where
    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors + WithStartNode,
{
    /// Performs a depth-first search, starting from `G::start_node()`.
    ///
    /// This won't visit nodes that are not reachable from the start node.
    pub fn run_from_start<V>(self, visitor: &mut V) -> Option<V::BreakVal>
    where
        V: TriColorVisitor<G>,
    {
        let root = self.graph.start_node();
        self.run_from(root, visitor)
    }
}

/// What to do when a node is examined or becomes `Settled` during DFS.
pub trait TriColorVisitor<G>
where
    G: ?Sized + DirectedGraph,
{
    /// The value returned by this search.
    type BreakVal;

    /// Called when a node is examined by the depth-first search.
    ///
    /// By checking the value of `prior_status`, this visitor can determine whether the edge
    /// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge
    /// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search"
    /// chapter in [CLR] or [wikipedia].
    ///
    /// If you want to know *both* nodes linked by each edge, you'll need to modify
    /// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event.
    ///
    /// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search
    /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
    fn node_examined(
        &mut self,
        _node: G::Node,
        _prior_status: Option<NodeStatus>,
    ) -> ControlFlow<Self::BreakVal> {
        ControlFlow::CONTINUE
    }

    /// Called after all nodes reachable from this one have been examined.
    fn node_settled(&mut self, _node: G::Node) -> ControlFlow<Self::BreakVal> {
        ControlFlow::CONTINUE
    }

    /// Behave as if no edges exist from `source` to `target`.
    fn ignore_edge(&mut self, _source: G::Node, _target: G::Node) -> bool {
        false
    }
}

/// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists.
pub struct CycleDetector;

impl<G> TriColorVisitor<G> for CycleDetector
where
    G: ?Sized + DirectedGraph,
{
    type BreakVal = ();

    fn node_examined(
        &mut self,
        _node: G::Node,
        prior_status: Option<NodeStatus>,
    ) -> ControlFlow<Self::BreakVal> {
        match prior_status {
            Some(NodeStatus::Visited) => ControlFlow::BREAK,
            _ => ControlFlow::CONTINUE,
        }
    }
}
<|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/. */

extern crate serde_json;

use foxbox_taxonomy::manager::WatchGuard;
use foxbox_taxonomy::api::{ API, TargetMap };
use foxbox_taxonomy::values::Value;
use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;

use foxbox_users::AuthEndpoint;

use iron::{ Handler, IronResult, Request, Response };
use iron::headers::ContentType;
use iron::method::Method;
use iron::prelude::Chain;
use iron::request::Body;
use iron::status::Status;

use std::io::{ Error as IOError, Read };
use std::sync::Mutex;
use traits::Controller;

/// This is a specialized Router for the taxonomy API.
/// It handles all the calls under the api/v1/ url space.
pub struct TaxonomyRouter {
    api: Mutex
}

impl TaxonomyRouter
    where A: API<WatchGuard=WatchGuard> + 'static {
    pub fn new(adapter_api: A) -> Self {
        TaxonomyRouter {
            // This locks the full api access when dealing with a http request,
            // which basically kills http concurrency.
            // TODO: make it concurrent again.
            api: Mutex::new(adapter_api)
        }
    }

    fn build_response<S: ToJSON>(&self, obj: &S) -> IronResult<Response> {
        let json = obj.to_json();
        let serialized = itry!(serde_json::to_string(&json));
        let mut response = Response::with(serialized);
        response.status = Some(Status::Ok);
        response.headers.set(ContentType::json());
        Ok(response)
    }

    fn read_body_to_string<'a, 'b : 'a>(body: &mut Body<'a, 'b>) -> Result<String, IOError> {
        let mut s = String::new();
        try!(body.read_to_string(&mut s));
        Ok(s)
    }
}

impl Handler for TaxonomyRouter
    where A: API<WatchGuard=WatchGuard> + 'static {

    #[allow(cyclomatic_complexity)]
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        // We are handled urls relative to the mounter set up in http_server.rs
        // That means that for a full url like http://localhost/api/v1/services
        // the req.url.path will only contain ["services"]
        let path = req.url.path.clone();

        /// Generates the code for a generic HTTP call, where we use an empty
        /// taxonomy selector for GET requests, and a decoded json body for POST ones.
        /// $call is the method we'll call on the api, like get_services.
        /// $sel  is the selector type, like ServiceSelector
        /// $path is a vector describing the url path, like ["service", "tags"]
        macro_rules! get_post_api {
            ($call:ident, $sel:ident, $path:expr) => (
            if path == $path {
                return {
                    let api = self.api.lock().unwrap();

                    if req.method != Method::Get && req.method != Method::Post {
                        // Wrong method, return a 405 error.
                        return Ok(Response::with((Status::MethodNotAllowed,
                                                  format!("Bad method: {}", req.method))));
                    }

                    let result = if req.method == Method::Get {
                        // On a GET, just send the full taxonomy content for
                        // this kind of selector.
                        api.$call(vec![$sel::new()])
                    } else {
                        let source = itry!(Self::read_body_to_string(&mut req.body));
                        let selectors = itry!(Vec::<$sel>::from_str(&source));
                        api.$call(selectors)
                    };

                    self.build_response(&result)
                }
            })
        }

        // Generates the code to process a given HTTP call with a json body.
        macro_rules! payload_api {
            ($call:ident, $param:ty, $path:expr, $method:expr) => (
                if path == $path && req.method == $method {
                    type Selectors = $param;
                    return {
                        let api = self.api.lock().unwrap();
                        let source = itry!(Self::read_body_to_string(&mut req.body));
                        let selectors = itry!(Selectors::from_str(&source));
                        let result = api.$call(selectors);
                        return self.build_response(&result);
                    }
                }
            )
        }

        // Generates the code to process a given HTTP call with a json body.
        // This version takes 2 parameters for the internal call.
        macro_rules! payload_api2 {
            ($call:ident, $name1:ident => $param1:ty, $name2:ident => $param2:ty, $path:expr, $method:expr) => (
                if path == $path && req.method == $method {
                    type Param1 = $param1;
                    type Param2 = $param2;
                    return {
                        let api = self.api.lock().unwrap();

                        let source = itry!(Self::read_body_to_string(&mut req.body));
                        let mut args: JSON = itry!(serde_json::de::from_str(&source));
                        let arg_1 = itry!(Param1::take(Path::new(), &mut args, stringify!($name1)));
                        let arg_2 = itry!(Param2::take(Path::new(), &mut args, stringify!($name2)));

                        let result = api.$call(arg_1, arg_2);
                        return self.build_response(&result);
                    }
                }
            )
        }

        // Keep these urls in sync with the AuthEndpoint(s) in the create() method.

        // Selectors queries.
        get_post_api!(get_services, ServiceSelector, ["services"]);
        get_post_api!(get_getter_channels, GetterSelector, ["channels", "getters"]);
        get_post_api!(get_setter_channels, SetterSelector, ["channels", "setters"]);

        // Fetching and getting values.
        payload_api!(fetch_values, Vec<GetterSelector>, ["channels", "get"], Method::Get);
        payload_api!(send_values, TargetMap<SetterSelector, Value>, ["channels", "set"], Method::Put);

        // Adding tags.
        payload_api2!(add_service_tags,
                      services => Vec<ServiceSelector>,
                      tags => Vec<Id<TagId>>,
                      ["services", "tags"], Method::Post);
        payload_api2!(add_getter_tags,
                      getters => Vec<GetterSelector>,
                      tags => Vec<Id<TagId>>,
                      ["channels", "getter", "tags"], Method::Post);
        payload_api2!(add_setter_tags,
                      setters => Vec<SetterSelector>,
                      tags => Vec<Id<TagId>>,
                      ["channels", "getter", "tags"], Method::Post);

        // Removing tags.
        payload_api2!(remove_service_tags,
                      services => Vec<ServiceSelector>,
                      tags => Vec<Id<TagId>>,
                      ["services", "tags"], Method::Delete);
        payload_api2!(remove_getter_tags,
                      getters => Vec<GetterSelector>,
                      tags => Vec<Id<TagId>>,
                      ["channels", "getter", "tags"], Method::Delete);
        payload_api2!(remove_setter_tags,
                      setters => Vec<SetterSelector>,
                      tags => Vec<Id<TagId>>,
                      ["channels", "getter", "tags"], Method::Delete);

        // Fallthrough, returning a 404.
        Ok(Response::with((Status::NotFound,
                           format!("Unknown url: {}", req.url))))
    }
}

pub fn create<T, A>(controller: T, adapter_api: A) -> Chain
    where A: API<WatchGuard=WatchGuard> + 'static,
          T: Controller {
    let router = TaxonomyRouter::new(adapter_api);

    let auth_endpoints = if cfg!(feature = "authentication") && !cfg!(test) {
        // Keep this list in sync with all the (url path, http method) from
        // the handle() method and with the CORS chain in http_server.rs
        vec![
            AuthEndpoint(vec![Method::Get, Method::Post], "services".to_owned()),
            AuthEndpoint(vec![Method::Post, Method::Delete], "services/tags".to_owned()),
            AuthEndpoint(vec![Method::Get, Method::Post], "channels/getters".to_owned()),
            AuthEndpoint(vec![Method::Get, Method::Post], "channels/setters".to_owned()),
            AuthEndpoint(vec![Method::Get], "channels/get".to_owned()),
            AuthEndpoint(vec![Method::Put], "channels/set".to_owned()),
            AuthEndpoint(vec![Method::Post, Method::Delete], "channel/getters/tags".to_owned()),
            AuthEndpoint(vec![Method::Post, Method::Delete], "channel/setters/tags".to_owned())
        ]
    } else {
        vec![]
    };

    let mut chain = Chain::new(router);
    chain.around(controller.get_users_manager().get_middleware(auth_endpoints));

    chain
}

#[cfg(test)]
describe! taxonomy_router {
    before_each {
        extern crate serde_json;

        use adapters::clock;
        use foxbox_taxonomy::manager::AdapterManager;
        use iron::Headers;
        use iron_test::{ request, response };
        use mount::Mount;
        use stubs::controller::ControllerStub;

        let taxo_manager = AdapterManager::new();
        clock::Clock::init(&taxo_manager).unwrap();

        let mut mount = Mount::new();
        mount.mount("/api/v1", create(ControllerStub::new(), taxo_manager));
    }

    it "should return the list of services from a GET request" {
        let response = request::get("http://localhost:3000/api/v1/services",
                                    Headers::new(),
                                    &mount).unwrap();
        let body = response::extract_body_to_string(response);
        let s = r#"[{"adapter":"clock@link.mozilla.org","getters":{"getter:timeofday.clock@link.mozilla.org":{"adapter":"clock@link.mozilla.org","id":"getter:timeofday.clock@link.mozilla.org","kind":"CurrentTimeOfDay","mechanism":"getter","service":"service:clock@link.mozilla.org","tags":[]},"getter:timestamp.clock@link.mozilla.org":{"adapter":"clock@link.mozilla.org","id":"getter:timestamp.clock@link.mozilla.org","kind":"CurrentTime","mechanism":"getter","service":"service:clock@link.mozilla.org","tags":[]}},"id":"service:clock@link.mozilla.org","properties":{"model":"Mozilla clock v1"},"setters":{},"tags":[]}]"#;

        assert_eq!(body, s);
    }

    it "should return the list of services from a POST request" {
        let response = request::post("http://localhost:3000/api/v1/services",
                                    Headers::new(),
                                    r#"[{"id":"service:clock@link.mozilla.org"}]"#,
                                    &mount).unwrap();
        let body = response::extract_body_to_string(response);
        let s = r#"[{"adapter":"clock@link.mozilla.org","getters":{"getter:timeofday.clock@link.mozilla.org":{"adapter":"clock@link.mozilla.org","id":"getter:timeofday.clock@link.mozilla.org","kind":"CurrentTimeOfDay","mechanism":"getter","service":"service:clock@link.mozilla.org","tags":[]},"getter:timestamp.clock@link.mozilla.org":{"adapter":"clock@link.mozilla.org","id":"getter:timestamp.clock@link.mozilla.org","kind":"CurrentTime","mechanism":"getter","service":"service:clock@link.mozilla.org","tags":[]}},"id":"service:clock@link.mozilla.org","properties":{"model":"Mozilla clock v1"},"setters":{},"tags":[]}]"#;

        assert_eq!(body, s);
    }
}
<commit_msg>Better error reporting, restored a few tests<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/. */

extern crate serde_json;

use foxbox_taxonomy::manager::WatchGuard;
use foxbox_taxonomy::api::{ API, TargetMap };
use foxbox_taxonomy::values::Value;
use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;

use foxbox_users::AuthEndpoint;

use iron::{ Handler, IronResult, Request, Response };
use iron::headers::ContentType;
use iron::method::Method;
use iron::prelude::Chain;
use iron::request::Body;
use iron::status::Status;

use std::io::{ Error as IOError, Read };
use std::sync::Mutex;
use traits::Controller;

/// This is a specialized Router for the taxonomy API.
/// It handles all the calls under the api/v1/ url space.
pub struct TaxonomyRouter {
    api: Mutex
}

impl TaxonomyRouter
    where A: API<WatchGuard=WatchGuard> + 'static {
    pub fn new(adapter_api: A) -> Self {
        TaxonomyRouter {
            // This locks the full api access when dealing with a http request,
            // which basically kills http concurrency.
            // TODO: make it concurrent again.
            api: Mutex::new(adapter_api)
        }
    }

    fn build_response<S: ToJSON>(&self, obj: &S) -> IronResult<Response> {
        let json = obj.to_json();
        let serialized = itry!(serde_json::to_string(&json));
        let mut response = Response::with(serialized);
        response.status = Some(Status::Ok);
        response.headers.set(ContentType::json());
        Ok(response)
    }

    fn build_parse_error(&self, obj: &ParseError) -> IronResult<Response> {
        let mut response = Response::with(format!("{}", obj));
        response.status = Some(Status::BadRequest);
        response.headers.set(ContentType::plaintext()); // FIXME: Should be JSON
        Ok(response)
    }

    fn read_body_to_string<'a, 'b : 'a>(body: &mut Body<'a, 'b>) -> Result<String, IOError> {
        let mut s = String::new();
        try!(body.read_to_string(&mut s));
        Ok(s)
    }
}

impl Handler for TaxonomyRouter
    where A: API<WatchGuard=WatchGuard> + 'static {

    #[allow(cyclomatic_complexity)]
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        // We are handled urls relative to the mounter set up in http_server.rs
        // That means that for a full url like http://localhost/api/v1/services
        // the req.url.path will only contain ["services"]
        let path = req.url.path.clone();

        /// Generates the code for a generic HTTP call, where we use an empty
        /// taxonomy selector for GET requests, and a decoded json body for POST ones.
        /// $call is the method we'll call on the api, like get_services.
        /// $sel  is the selector type, like ServiceSelector
        /// $path is a vector describing the url path, like ["service", "tags"]
        macro_rules! get_post_api {
            ($call:ident, $sel:ident, $path:expr) => (
            if path == $path {
                return {
                    let api = self.api.lock().unwrap();

                    if req.method != Method::Get && req.method != Method::Post {
                        // Wrong method, return a 405 error.
                        return Ok(Response::with((Status::MethodNotAllowed,
                                                  format!("Bad method: {}", req.method))));
                    }

                    if req.method == Method::Get {
                        // On a GET, just send the full taxonomy content for
                        // this kind of selector.
                        let result = api.$call(vec![$sel::new()]);
                        self.build_response(&result)
                    } else {
                        let source = itry!(Self::read_body_to_string(&mut req.body));
                        match Vec::<$sel>::from_str(&source as &str) {
                            Ok(arg) => self.build_response(&api.$call(arg)),
                            Err(err) => self.build_parse_error(&err)
                        }
                    }
                }
            })
        }

        // Generates the code to process a given HTTP call with a json body.
        macro_rules! payload_api {
            ($call:ident, $param:ty, $path:expr, $method:expr) => (
                if path == $path && req.method == $method {
                    type Selectors = $param;
                    return {
                        let api = self.api.lock().unwrap();
                        let source = itry!(Self::read_body_to_string(&mut req.body));
                        match Selectors::from_str(&source as &str) {
                            Ok(arg) => self.build_response(&api.$call(arg)),
                            Err(err) => self.build_parse_error(&err)
                        }
                    }
                }
            )
        }

        // Generates the code to process a given HTTP call with a json body.
        // This version takes 2 parameters for the internal call.
        macro_rules! payload_api2 {
            ($call:ident, $name1:ident => $param1:ty, $name2:ident => $param2:ty, $path:expr, $method:expr) => (
                if path == $path && req.method == $method {
                    type Param1 = $param1;
                    type Param2 = $param2;
                    return {
                        let api = self.api.lock().unwrap();

                        let source = itry!(Self::read_body_to_string(&mut req.body));
                        let mut json = match serde_json::de::from_str(&source as &str) {
                            Err(err) => return self.build_parse_error(&ParseError::json(err)),
                            Ok(args) => args
                        };
                        let arg_1 = match Param1::take(Path::new(), &mut json, stringify!($name1)) {
                            Err(err) => return self.build_parse_error(&err),
                            Ok(val) => val
                        };
                        let arg_2 = match Param2::take(Path::new(), &mut json, stringify!($name2)) {
                            Err(err) => return self.build_parse_error(&err),
                            Ok(val) => val
                        };
                        self.build_response(&api.$call(arg_1, arg_2))
                    }
                }
            )
        }

        // Keep these urls in sync with the AuthEndpoint(s) in the create() method.

        // Selectors queries.
        get_post_api!(get_services, ServiceSelector, ["services"]);
        get_post_api!(get_getter_channels, GetterSelector, ["channels", "getters"]);
        get_post_api!(get_setter_channels, SetterSelector, ["channels", "setters"]);

        // Fetching and getting values.
        payload_api!(fetch_values, Vec<GetterSelector>, ["channels", "get"], Method::Get);
        payload_api!(send_values, TargetMap<SetterSelector, Value>, ["channels", "set"], Method::Put);

        // Adding tags.
        payload_api2!(add_service_tags,
                      services => Vec<ServiceSelector>,
                      tags => Vec<Id<TagId>>,
                      ["services", "tags"], Method::Post);
        payload_api2!(add_getter_tags,
                      getters => Vec<GetterSelector>,
                      tags => Vec<Id<TagId>>,
                      ["channels", "getter", "tags"], Method::Post);
        payload_api2!(add_setter_tags,
                      setters => Vec<SetterSelector>,
                      tags => Vec<Id<TagId>>,
                      ["channels", "getter", "tags"], Method::Post);

        // Removing tags.
        payload_api2!(remove_service_tags,
                      services => Vec<ServiceSelector>,
                      tags => Vec<Id<TagId>>,
                      ["services", "tags"], Method::Delete);
        payload_api2!(remove_getter_tags,
                      getters => Vec<GetterSelector>,
                      tags => Vec<Id<TagId>>,
                      ["channels", "getter", "tags"], Method::Delete);
        payload_api2!(remove_setter_tags,
                      setters => Vec<SetterSelector>,
                      tags => Vec<Id<TagId>>,
                      ["channels", "getter", "tags"], Method::Delete);

        // Fallthrough, returning a 404.
        Ok(Response::with((Status::NotFound,
                           format!("Unknown url: {}", req.url))))
    }
}

pub fn create<T, A>(controller: T, adapter_api: A) -> Chain
    where A: API<WatchGuard=WatchGuard> + 'static,
          T: Controller {
    let router = TaxonomyRouter::new(adapter_api);

    let auth_endpoints = if cfg!(feature = "authentication") && !cfg!(test) {
        // Keep this list in sync with all the (url path, http method) from
        // the handle() method and with the CORS chain in http_server.rs
        vec![
            AuthEndpoint(vec![Method::Get, Method::Post], "services".to_owned()),
            AuthEndpoint(vec![Method::Post, Method::Delete], "services/tags".to_owned()),
            AuthEndpoint(vec![Method::Get, Method::Post], "channels/getters".to_owned()),
            AuthEndpoint(vec![Method::Get, Method::Post], "channels/setters".to_owned()),
            AuthEndpoint(vec![Method::Get], "channels/get".to_owned()),
            AuthEndpoint(vec![Method::Put], "channels/set".to_owned()),
            AuthEndpoint(vec![Method::Post, Method::Delete], "channel/getters/tags".to_owned()),
            AuthEndpoint(vec![Method::Post, Method::Delete], "channel/setters/tags".to_owned())
        ]
    } else {
        vec![]
    };

    let mut chain = Chain::new(router);
    chain.around(controller.get_users_manager().get_middleware(auth_endpoints));

    chain
}

#[cfg(test)]
describe! taxonomy_router {
    before_each {
        extern crate serde_json;

        use serde_json::value::Value as JSON;
        use adapters::clock;
        use foxbox_taxonomy::manager::AdapterManager;
        use iron::Headers;
        use iron_test::{ request, response };
        use mount::Mount;
        use stubs::controller::ControllerStub;

        let taxo_manager = AdapterManager::new();
        clock::Clock::init(&taxo_manager).unwrap();

        let mut mount = Mount::new();
        mount.mount("/api/v1", create(ControllerStub::new(), taxo_manager));
    }

    it "should return the list of services from a GET request" {
        let response = request::get("http://localhost:3000/api/v1/services",
                                    Headers::new(),
                                    &mount).unwrap();
        let body = response::extract_body_to_string(response);
        let s = r#"[{"adapter":"clock@link.mozilla.org","getters":{"getter:timeofday.clock@link.mozilla.org":{"adapter":"clock@link.mozilla.org","id":"getter:timeofday.clock@link.mozilla.org","kind":"CurrentTimeOfDay","mechanism":"getter","service":"service:clock@link.mozilla.org","tags":[]},"getter:timestamp.clock@link.mozilla.org":{"adapter":"clock@link.mozilla.org","id":"getter:timestamp.clock@link.mozilla.org","kind":"CurrentTime","mechanism":"getter","service":"service:clock@link.mozilla.org","tags":[]}},"id":"service:clock@link.mozilla.org","properties":{"model":"Mozilla clock v1"},"setters":{},"tags":[]}]"#;

        assert_eq!(body, s);
    }

    it "should return the list of services from a POST request" {
        let response = request::post("http://localhost:3000/api/v1/services",
                                    Headers::new(),
                                    r#"[{"id":"service:clock@link.mozilla.org"}]"#,
                                    &mount).unwrap();
        let body = response::extract_body_to_string(response);
        let s = r#"[{"adapter":"clock@link.mozilla.org","getters":{"getter:timeofday.clock@link.mozilla.org":{"adapter":"clock@link.mozilla.org","id":"getter:timeofday.clock@link.mozilla.org","kind":"CurrentTimeOfDay","mechanism":"getter","service":"service:clock@link.mozilla.org","tags":[]},"getter:timestamp.clock@link.mozilla.org":{"adapter":"clock@link.mozilla.org","id":"getter:timestamp.clock@link.mozilla.org","kind":"CurrentTime","mechanism":"getter","service":"service:clock@link.mozilla.org","tags":[]}},"id":"service:clock@link.mozilla.org","properties":{"model":"Mozilla clock v1"},"setters":{},"tags":[]}]"#;

        assert_eq!(body, s);
    }
}
<|endoftext|>