<commit_before>use bifrost::conshash::{CHError, ConsistentHashing};
use bifrost::membership::client::ObserverClient;
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::{RPCClient, RPCError, Server as RPCServer, DEFAULT_CLIENT_POOL};
use futures::prelude::*;
use futures::stream::FuturesUnordered;
use futures::stream::StreamExt;
use itertools::Itertools;
use std::cell::Cell as StdCell;
use std::collections::HashMap;
use std::io;
use std::mem;
use std::sync::Arc;

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

use self::transaction::*;

static TRANSACTION_MAX_RETRY: u32 = 1000;

#[cfg(test)]
mod tests;
pub mod transaction;

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

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

pub fn client_by_rpc_client(rpc: &Arc<RPCClient>) -> Arc<plain_server::AsyncServiceClient> {
    plain_server::AsyncServiceClient::new(plain_server::DEFAULT_SERVICE_ID, rpc)
}

impl AsyncClient {
    pub async fn new<'a>(
        subscription_server: &Arc<RPCServer>,
        membership: &Arc<ObserverClient>,
        meta_servers: &Vec<String>,
        group: &'a str,
    ) -> Result<Self, NebClientError> {
        match RaftClient::new(meta_servers, raft::DEFAULT_SERVICE_ID).await {
            Ok(raft_client) => {
                RaftClient::prepare_subscription(subscription_server).await;
                assert!(RaftClient::can_callback().await);
                match ConsistentHashing::new_client_with_id(
                    CONS_HASH_ID,
                    group,
                    &raft_client,
                    membership,
                )
                .await
                {
                    Ok(chash) => Ok(Self {
                        conshash: chash,
                        raft_client: raft_client.clone(),
                        schema_client: SchemaClient::new(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> {
        if id.is_unit_id() {
            return Ok(0);
        }
        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 async fn client_by_server_id(
        &self,
        server_id: u64,
    ) -> Result<Arc<plain_server::AsyncServiceClient>, RPCError> {
        DEFAULT_CLIENT_POOL
            .get_by_id(server_id, move |sid| self.conshash.to_server_name(sid))
            .await
            .map_err(|e| RPCError::IOError(e))
            .map(|c| client_by_rpc_client(&c))
    }

    pub async fn locate_plain_server(
        &self,
        id: Id,
    ) -> Result<Arc<plain_server::AsyncServiceClient>, RPCError> {
        let server_id = self.locate_server_id(&id).unwrap();
        debug_assert!(server_id > 0, "Have server id 0 for id {:?}", id);
        self.client_by_server_id(server_id).await
    }

    pub async fn read_cell(&self, id: Id) -> Result<Result<Cell, ReadError>, RPCError> {
        let client = self.locate_plain_server(id).await?;
        client.read_cell(id).await
    }
    pub async fn read_all_cells(
        &self,
        ids: Vec<Id>,
    ) -> Result<Vec<Result<Cell, ReadError>>, RPCError> {
        let mut cells_by_client = ids
            .iter()
            .dedup()
            .group_by(|id| self.locate_server_id(&id).unwrap())
            .into_iter()
            .map(|(server_id, ids)| (server_id, ids.map(|id| *id).collect_vec()))
            .map(|(server_id, ids)| async move {
                if server_id > 0 {
                    let client = self.client_by_server_id(server_id).await.unwrap();
                    (client.read_all_cells(ids.clone()).await, ids)
                } else {
                    (
                        Ok(vec![Err(ReadError::CellIdIsUnitId)]),
                        vec![Id::unit_id()],
                    )
                }
            })
            .collect::<FuturesUnordered<_>>();
        let mut id_cell_map = HashMap::new();
        while let Some((cells, ids)) = cells_by_client.next().await {
            let cells = cells?;
            for (id, cell) in ids.into_iter().zip(cells) {
                id_cell_map.insert(id, Some(cell));
            }
        }
        Ok(ids
            .iter()
            .map(|id| {
                // Use mem::replace to avoid additional cost when hash map shriking by remove
                let id_ref = id_cell_map.get_mut(id).unwrap();
                mem::replace(id_ref, None).unwrap()
            })
            .collect())
    }
    pub async fn write_cell(&self, cell: Cell) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = self.locate_plain_server(cell.id()).await?;
        client.write_cell(cell).await
    }
    pub async fn update_cell(
        &self,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = self.locate_plain_server(cell.id()).await?;
        client.update_cell(cell).await
    }
    pub async fn upsert_cell(
        &self,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = self.locate_plain_server(cell.id()).await?;
        client.upsert_cell(cell).await
    }
    pub async fn remove_cell(&self, id: Id) -> Result<Result<(), WriteError>, RPCError> {
        let client = self.locate_plain_server(id).await?;
        client.remove_cell(id).await
    }
    pub async fn count(&self) -> Result<u64, RPCError> {
        let (members, _) = self.conshash.membership().all_members(true).await.unwrap();
        let mut member_futs: FuturesUnordered<_> = members
            .into_iter()
            .map(|m| async move {
                let client = self.client_by_server_id(m.id).await?;
                Ok(client.count().await?)
            })
            .collect();
        let mut sum = 0;
        while let Some(res) = member_futs.next().await {
            sum += res?;
        }
        Ok(sum)
    }
    pub async fn transaction<'a, TFN, TR, RF>(&self, func: TFN) -> Result<TR, TxnError>
    where
        TFN: Fn(Transaction) -> RF + 'a,
        RF: Future<Output = Result<TR, TxnError>> + 'a,
    {
        let server_name = match self.conshash.rand_server() {
            Some(name) => name,
            None => return Err(TxnError::CannotFindAServer),
        };
        let txn_client = match txn_server::new_async_client(&server_name).await {
            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 txn_client.begin().await {
                Ok(Ok(id)) => id,
                _ => return Err(TxnError::CannotBegin),
            };
            let txn = Transaction {
                tid: txn_id,
                state: Arc::new(StdCell::new(txn_server::TxnState::Started)),
                client: txn_client.clone(),
            };
            let exec_result = func(txn.clone()).await;
            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().await;
                        debug!("PREPARE STATE: {:?}", txn_result);
                    }
                    if txn_result.is_ok() && txn.state.get() == txn_server::TxnState::Prepared {
                        txn_result = txn.commit().await;
                        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().await; // 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().await;
                    debug!("TXN ERROR, ABORT: {:?}", abort_result);
                    return Err(e);
                }
            }
            retried += 1;
            debug!("Client retry transaction, {:?} times", retried);
        }
        Err(TxnError::TooManyRetry)
    }
    pub async fn new_schema_with_id(
        &self,
        schema: Schema,
    ) -> Result<Result<(), NotifyError>, ExecError> {
        self.schema_client.new_schema(&schema).await
    }
    pub async fn new_schema(
        &self,
        mut schema: Schema,
    ) -> Result<(u32, Option<NotifyError>), ExecError> {
        let schema_id = self.schema_client.next_id().await?;
        schema.id = schema_id;
        self.new_schema_with_id(schema).await.map(|r| {
            let error = match r {
                Ok(_) => None,
                Err(e) => Some(e),
            };
            (schema_id, error)
        })
    }
    pub async fn del_schema(&self, name: String) -> Result<Result<(), NotifyError>, ExecError> {
        self.schema_client.del_schema(&name).await
    }
    pub async fn get_all_schema(&self) -> Result<Vec<Schema>, ExecError> {
        self.schema_client.get_all().await
    }
}
<commit_msg>promote read all cell errors<commit_after>use bifrost::conshash::{CHError, ConsistentHashing};
use bifrost::membership::client::ObserverClient;
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::{RPCClient, RPCError, Server as RPCServer, DEFAULT_CLIENT_POOL};
use futures::prelude::*;
use futures::stream::FuturesUnordered;
use futures::stream::StreamExt;
use itertools::Itertools;
use std::cell::Cell as StdCell;
use std::collections::HashMap;
use std::io;
use std::mem;
use std::sync::Arc;

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

use self::transaction::*;

static TRANSACTION_MAX_RETRY: u32 = 1000;

#[cfg(test)]
mod tests;
pub mod transaction;

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

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

pub fn client_by_rpc_client(rpc: &Arc<RPCClient>) -> Arc<plain_server::AsyncServiceClient> {
    plain_server::AsyncServiceClient::new(plain_server::DEFAULT_SERVICE_ID, rpc)
}

impl AsyncClient {
    pub async fn new<'a>(
        subscription_server: &Arc<RPCServer>,
        membership: &Arc<ObserverClient>,
        meta_servers: &Vec<String>,
        group: &'a str,
    ) -> Result<Self, NebClientError> {
        match RaftClient::new(meta_servers, raft::DEFAULT_SERVICE_ID).await {
            Ok(raft_client) => {
                RaftClient::prepare_subscription(subscription_server).await;
                assert!(RaftClient::can_callback().await);
                match ConsistentHashing::new_client_with_id(
                    CONS_HASH_ID,
                    group,
                    &raft_client,
                    membership,
                )
                .await
                {
                    Ok(chash) => Ok(Self {
                        conshash: chash,
                        raft_client: raft_client.clone(),
                        schema_client: SchemaClient::new(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> {
        if id.is_unit_id() {
            return Ok(0);
        }
        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 async fn client_by_server_id(
        &self,
        server_id: u64,
    ) -> Result<Arc<plain_server::AsyncServiceClient>, RPCError> {
        DEFAULT_CLIENT_POOL
            .get_by_id(server_id, move |sid| self.conshash.to_server_name(sid))
            .await
            .map_err(|e| RPCError::IOError(e))
            .map(|c| client_by_rpc_client(&c))
    }

    pub async fn locate_plain_server(
        &self,
        id: Id,
    ) -> Result<Arc<plain_server::AsyncServiceClient>, RPCError> {
        let server_id = self.locate_server_id(&id).unwrap();
        debug_assert!(server_id > 0, "Have server id 0 for id {:?}", id);
        self.client_by_server_id(server_id).await
    }

    pub async fn read_cell(&self, id: Id) -> Result<Result<Cell, ReadError>, RPCError> {
        let client = self.locate_plain_server(id).await?;
        client.read_cell(id).await
    }
    pub async fn read_all_cells(
        &self,
        ids: Vec<Id>,
    ) -> Result<Vec<Result<Cell, ReadError>>, RPCError> {
        let mut cells_by_client = ids
            .iter()
            .dedup()
            .group_by(|id| self.locate_server_id(&id).unwrap())
            .into_iter()
            .map(|(server_id, ids)| (server_id, ids.map(|id| *id).collect_vec()))
            .map(|(server_id, ids)| async move {
                if server_id > 0 {
                    let client = self.client_by_server_id(server_id).await.unwrap();
                    (client.read_all_cells(ids.clone()).await, ids)
                } else {
                    (
                        Ok(vec![Err(ReadError::CellIdIsUnitId)]),
                        vec![Id::unit_id()],
                    )
                }
            })
            .collect::<FuturesUnordered<_>>();
        let mut id_cell_map = HashMap::new();
        while let Some((cells, ids)) = cells_by_client.next().await {
            let cells = cells?;
            for (id, cell) in ids.into_iter().zip(cells) {
                id_cell_map.insert(id, Some(cell));
            }
        }
        Ok(ids
            .iter()
            .map(|id| {
                // Use mem::replace to avoid additional cost when hash map shriking by remove
                let id_ref = id_cell_map.get_mut(id).unwrap();
                if cfg!(debug_assertions) && id_ref.is_none() {
                    let msg = format!("Cannot find {:?} for read_all_cells", id);
                    error!("{}", msg);
                    panic!(msg);
                }
                mem::replace(id_ref, None).unwrap()
            })
            .collect())
    }
    pub async fn write_cell(&self, cell: Cell) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = self.locate_plain_server(cell.id()).await?;
        client.write_cell(cell).await
    }
    pub async fn update_cell(
        &self,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = self.locate_plain_server(cell.id()).await?;
        client.update_cell(cell).await
    }
    pub async fn upsert_cell(
        &self,
        cell: Cell,
    ) -> Result<Result<CellHeader, WriteError>, RPCError> {
        let client = self.locate_plain_server(cell.id()).await?;
        client.upsert_cell(cell).await
    }
    pub async fn remove_cell(&self, id: Id) -> Result<Result<(), WriteError>, RPCError> {
        let client = self.locate_plain_server(id).await?;
        client.remove_cell(id).await
    }
    pub async fn count(&self) -> Result<u64, RPCError> {
        let (members, _) = self.conshash.membership().all_members(true).await.unwrap();
        let mut member_futs: FuturesUnordered<_> = members
            .into_iter()
            .map(|m| async move {
                let client = self.client_by_server_id(m.id).await?;
                Ok(client.count().await?)
            })
            .collect();
        let mut sum = 0;
        while let Some(res) = member_futs.next().await {
            sum += res?;
        }
        Ok(sum)
    }
    pub async fn transaction<'a, TFN, TR, RF>(&self, func: TFN) -> Result<TR, TxnError>
    where
        TFN: Fn(Transaction) -> RF + 'a,
        RF: Future<Output = Result<TR, TxnError>> + 'a,
    {
        let server_name = match self.conshash.rand_server() {
            Some(name) => name,
            None => return Err(TxnError::CannotFindAServer),
        };
        let txn_client = match txn_server::new_async_client(&server_name).await {
            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 txn_client.begin().await {
                Ok(Ok(id)) => id,
                _ => return Err(TxnError::CannotBegin),
            };
            let txn = Transaction {
                tid: txn_id,
                state: Arc::new(StdCell::new(txn_server::TxnState::Started)),
                client: txn_client.clone(),
            };
            let exec_result = func(txn.clone()).await;
            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().await;
                        debug!("PREPARE STATE: {:?}", txn_result);
                    }
                    if txn_result.is_ok() && txn.state.get() == txn_server::TxnState::Prepared {
                        txn_result = txn.commit().await;
                        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().await; // 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().await;
                    debug!("TXN ERROR, ABORT: {:?}", abort_result);
                    return Err(e);
                }
            }
            retried += 1;
            debug!("Client retry transaction, {:?} times", retried);
        }
        Err(TxnError::TooManyRetry)
    }
    pub async fn new_schema_with_id(
        &self,
        schema: Schema,
    ) -> Result<Result<(), NotifyError>, ExecError> {
        self.schema_client.new_schema(&schema).await
    }
    pub async fn new_schema(
        &self,
        mut schema: Schema,
    ) -> Result<(u32, Option<NotifyError>), ExecError> {
        let schema_id = self.schema_client.next_id().await?;
        schema.id = schema_id;
        self.new_schema_with_id(schema).await.map(|r| {
            let error = match r {
                Ok(_) => None,
                Err(e) => Some(e),
            };
            (schema_id, error)
        })
    }
    pub async fn del_schema(&self, name: String) -> Result<Result<(), NotifyError>, ExecError> {
        self.schema_client.del_schema(&name).await
    }
    pub async fn get_all_schema(&self) -> Result<Vec<Schema>, ExecError> {
        self.schema_client.get_all().await
    }
}
<|endoftext|>


<commit_before>#![crate_name = "nntp"]
#![crate_type = "lib"]

use std::string::String;
use std::io::{IoResult, TcpStream, IoError};
use std::io::IoErrorKind::OtherIoError;
use std::vec::Vec;

pub struct NNTPStream {
	stream: TcpStream,
	pub host: &'static str,
	pub port: u16
}

impl NNTPStream {

	pub fn connect(host: &'static str, port: u16) -> IoResult<NNTPStream> {
		let connect_string = format!("{}:{}", host, port);
		let tcp_stream = try!(TcpStream::connect(connect_string.as_slice()));
		let mut socket = NNTPStream { stream: tcp_stream, host: host, port: port };

		match socket.read_response(200) {
			Ok(_) => (),
			Err(_) => return Err(IoError{ kind: OtherIoError, desc: "Failed to read greeting response", detail: None})
		}

		Ok(socket)
	}

	pub fn article(&mut self) -> Result<Vec<String>, String> {
		self.retrieve_article(format!("ARTICLE\r\n").as_slice())
	}

	pub fn article_by_id(&mut self, article_id: &str) -> Result<Vec<String>, String> {
		self.retrieve_article(format!("ARTICLE {}\r\n", article_id).as_slice())
	}

	pub fn article_by_number(&mut self, article_number: int) -> Result<Vec<String>, String> {
		self.retrieve_article(format!("ARTICLE {}\r\n", article_number).as_slice())
	}

	fn retrieve_article(&mut self, article_command: &str) -> Result<Vec<String>, String> {
		self.stream.write_str(article_command.as_slice());

		match self.read_response(220) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	pub fn body(&mut self) -> Result<Vec<String>, String> {
		self.retrieve_body(format!("BODY\r\n").as_slice())
	}

	pub fn body_by_id(&mut self, article_id: &str) -> Result<Vec<String>, String> {
		self.retrieve_body(format!("BODY {}\r\n", article_id).as_slice())
	}

	pub fn body_by_number(&mut self, article_number: int) -> Result<Vec<String>, String> {
		self.retrieve_body(format!("BODY {}\r\n", article_number).as_slice())
	}

	fn retrieve_body(&mut self, body_command: &str) -> Result<Vec<String>, String> {
		self.stream.write_str(body_command.as_slice());

		match self.read_response(222) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	pub fn capabilities(&mut self) -> Result<Vec<String>, String> {
		let capabilities_command = format!("CAPABILITIES\r\n");

		self.stream.write_str(capabilities_command.as_slice());

		match self.read_response(101) {
			Ok(_) => (),
			Err(e) => return Err(format!("{}", e))
		}

		self.read_multiline_response()
	}

	pub fn date(&mut self) -> Result<String, String> {
		let date_command = format!("DATE\r\n");

		self.stream.write_str(date_command.as_slice());

		match self.read_response(111) {
			Ok((_, message)) => Ok(message),
			Err(e) => Err(e)
		}
	}

	pub fn head(&mut self) -> Result<Vec<String>, String> {
		self.retrieve_head(format!("HEAD\r\n").as_slice())
	}

	pub fn head_by_id(&mut self, article_id: &str) -> Result<Vec<String>, String> {
		self.retrieve_head(format!("HEAD {}\r\n", article_id).as_slice())
	}

	pub fn head_by_number(&mut self, article_number: int) -> Result<Vec<String>, String> {
		self.retrieve_head(format!("HEAD {}\r\n", article_number).as_slice())
	}

	fn retrieve_head(&mut self, head_command: &str) -> Result<Vec<String>, String> {
		self.stream.write_str(head_command.as_slice());

		match self.read_response(221) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	pub fn last(&mut self) -> Result<String, String> {
		let last_command = format!("LAST\r\n");

		self.stream.write_str(last_command.as_slice());

		match self.read_response(223) {
			Ok((_, message)) => Ok(message),
			Err(e) => Err(e)
		}
	}

	pub fn list(&mut self) -> Result<Vec<String>, String> {
		let list_command = format!("LIST\r\n");

		self.stream.write_str(list_command.as_slice());

		match self.read_response(215) {
			Ok(_) => (),
			Err(e) => return Err(format!("{}", e))
		}

		self.read_multiline_response()
	}

	pub fn group(&mut self, group: &str) -> Result<(), String> {
		let group_command = format!("GROUP {}\r\n", group);

		self.stream.write_str(group_command.as_slice());

		match self.read_response(211) {
			Ok(_) => Ok(()),
			Err(e) => Err(format!("{}", e))
		}
	}

	pub fn help(&mut self) -> Result<Vec<String>, String> {
		let help_command = format!("HELP\r\n");

		self.stream.write_str(help_command.as_slice());

		match self.read_response(100) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	pub fn quit(&mut self) -> Result<(), String> {
		let quit_command = format!("QUIT\r\n");
		self.stream.write_str(quit_command.as_slice());

		match self.read_response(205) {
			Ok(_) => Ok(()),
			Err(e) => Err(format!("{}", e))
		}
	}

	pub fn newgroups(&mut self, date: &str, time: &str, use_gmt: bool) -> Result<Vec<String>, String> {
		let newgroups_command = match use_gmt {
			true => format!("NEWSGROUP {} {} GMT\r\n", date, time),
			false => format!("NEWSGROUP {} {}\r\n", date, time)
		};

		self.stream.write_str(newgroups_command.as_slice());

		match self.read_response(231) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	pub fn newnews(&mut self, wildmat: &str, date: &str, time: &str, use_gmt: bool) -> Result<Vec<String>, String> {
		let newnews_command = match use_gmt {
			true => format!("NEWNEWS {} {} {} GMT\r\n", wildmat, date, time),
			false => format!("NEWNEWS {} {} {}\r\n", wildmat, date, time)
		};

		self.stream.write_str(newnews_command.as_slice());

		match self.read_response(230) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	pub fn next(&mut self) -> Result<String, String> {
		let next_command = format!("NEXT\r\n");
		self.stream.write_str(next_command.as_slice());

		match self.read_response(223) {
			Ok((_, message)) => Ok(message),
			Err(e) => Err(e)
		}
	}

	pub fn post(&mut self, message: &str) -> Result<(), String> {
		if !self.is_valid_message(message) {
			return Err(format!("Invalid message format. Message must end with \"\r\n.\r\n\""));
		}

		let post_command = format!("POST\r\n");

		self.stream.write_str(post_command.as_slice());

		match self.read_response(340) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		self.stream.write_str(message);

		match self.read_response(240) {
			Ok(_) => Ok(()),
			Err(e) => Err(e)
		}
	}

	pub fn stat(&mut self) -> Result<String, String> {
		self.retrieve_stat(format!("STAT\r\n").as_slice())
	}

	pub fn stat_by_id(&mut self, article_id: &str) -> Result<String, String> {
		self.retrieve_stat(format!("STAT {}\r\n", article_id).as_slice())
	}

	pub fn stat_by_number(&mut self, article_number: int) -> Result<String, String> {
		self.retrieve_stat(format!("STAT {}\r\n", article_number).as_slice())
	}

	fn retrieve_stat(&mut self, stat_command: &str) -> Result<String, String> {
		self.stream.write_str(stat_command.as_slice());

		match self.read_response(223) {
			Ok((_, message)) => Ok(message),
			Err(e) => Err(e)
		}
	}

	fn is_valid_message(&mut self, message: &str) -> bool {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		//Dot
		let dot = 0x2e;
		let message_string = String::from_str(message);
		let message_bytes = message_string.as_bytes();
		let length = message_string.len();

		return length >= 5 && (message_bytes[length-1] == lf && message_bytes[length-2] == cr &&
			message_bytes[length-3] == dot && message_bytes[length-4] == lf && message_bytes[length-5] == cr)
	}

	//Retrieve single line response
	fn read_response(&mut self, expected_code: int) -> Result<(int, String), String> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut line_buffer: Vec<u8> = Vec::new();

		while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.stream.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => return Err(format!("Error reading response")),
				}
				line_buffer.push(byte_buffer[0]);
		}

		let response = String::from_utf8(line_buffer).unwrap();
		let chars_to_trim: &[char] = &['\r', '\n'];
		let trimmed_response = response.as_slice().trim_chars(chars_to_trim);
    	let trimmed_response_vec: Vec<char> = trimmed_response.chars().collect();
    	if trimmed_response_vec.len() < 5 || trimmed_response_vec[3] != ' ' {
    		return Err(format!("Invalid response"));
    	}

    	let v: Vec<&str> = trimmed_response.splitn(1, ' ').collect();
    	let code: int = from_str(v[0]).unwrap();
    	let message = v[1];
    	if code != expected_code {
    		return Err(format!("Invalid response: {} {}", code, message))
    	}
    	Ok((code, String::from_str(message)))
	}

	fn read_multiline_response(&mut self) -> Result<Vec<String>, String> {
		let mut response: Vec<String> = Vec::new();
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut line_buffer: Vec<u8> = Vec::new();
		let mut complete = false;

		while !complete {
			while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.stream.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => println!("Error Reading!"),
				}
				line_buffer.push(byte_buffer[0]);
			}

			match String::from_utf8(line_buffer.clone()) {
        		Ok(res) => {
        			if res == format!(".\r\n") {
        				complete = true;
        			}
        			else {
          				response.push(res.clone());
            			line_buffer = Vec::new();
            		}
        		},
        		Err(e) => return Err(format!("{}",e))
      		}
		}
		Ok(response)
	}
}<commit_msg>Adding some rustdoc comments<commit_after>#![crate_name = "nntp"]
#![crate_type = "lib"]

use std::string::String;
use std::io::{IoResult, TcpStream, IoError};
use std::io::IoErrorKind::OtherIoError;
use std::vec::Vec;

/// Stream to be used for interfacing a NNTP server.
pub struct NNTPStream {
	stream: TcpStream,
	pub host: &'static str,
	pub port: u16
}

impl NNTPStream {

	/// Creates an NNTP Stream.
	pub fn connect(host: &'static str, port: u16) -> IoResult<NNTPStream> {
		let connect_string = format!("{}:{}", host, port);
		let tcp_stream = try!(TcpStream::connect(connect_string.as_slice()));
		let mut socket = NNTPStream { stream: tcp_stream, host: host, port: port };

		match socket.read_response(200) {
			Ok(_) => (),
			Err(_) => return Err(IoError{ kind: OtherIoError, desc: "Failed to read greeting response", detail: None})
		}

		Ok(socket)
	}

	/// The article indicated by the current article number in the currently selected newsgroup is selected.
	pub fn article(&mut self) -> Result<Vec<String>, String> {
		self.retrieve_article(format!("ARTICLE\r\n").as_slice())
	}

	/// The article indicated by the article id is selected.
	pub fn article_by_id(&mut self, article_id: &str) -> Result<Vec<String>, String> {
		self.retrieve_article(format!("ARTICLE {}\r\n", article_id).as_slice())
	}

	/// The article indicated by the article number in the currently selected newsgroup is selected.
	pub fn article_by_number(&mut self, article_number: int) -> Result<Vec<String>, String> {
		self.retrieve_article(format!("ARTICLE {}\r\n", article_number).as_slice())
	}

	fn retrieve_article(&mut self, article_command: &str) -> Result<Vec<String>, String> {
		self.stream.write_str(article_command.as_slice());

		match self.read_response(220) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	/// Retrieves the body of the current article number in the currently selected newsgroup.
	pub fn body(&mut self) -> Result<Vec<String>, String> {
		self.retrieve_body(format!("BODY\r\n").as_slice())
	}

	/// Retrieves the body of the article id.
	pub fn body_by_id(&mut self, article_id: &str) -> Result<Vec<String>, String> {
		self.retrieve_body(format!("BODY {}\r\n", article_id).as_slice())
	}

	/// Retrieves the body of the article number in the currently selected newsgroup.
	pub fn body_by_number(&mut self, article_number: int) -> Result<Vec<String>, String> {
		self.retrieve_body(format!("BODY {}\r\n", article_number).as_slice())
	}

	fn retrieve_body(&mut self, body_command: &str) -> Result<Vec<String>, String> {
		self.stream.write_str(body_command.as_slice());

		match self.read_response(222) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	/// Gives the list of capabilities that the server has.
	pub fn capabilities(&mut self) -> Result<Vec<String>, String> {
		let capabilities_command = format!("CAPABILITIES\r\n");

		self.stream.write_str(capabilities_command.as_slice());

		match self.read_response(101) {
			Ok(_) => (),
			Err(e) => return Err(format!("{}", e))
		}

		self.read_multiline_response()
	}

	/// Retrieves the date as the server sees the date.
	pub fn date(&mut self) -> Result<String, String> {
		let date_command = format!("DATE\r\n");

		self.stream.write_str(date_command.as_slice());

		match self.read_response(111) {
			Ok((_, message)) => Ok(message),
			Err(e) => Err(e)
		}
	}

	/// /// Retrieves the head of the current article number in the currently selected newsgroup.
	pub fn head(&mut self) -> Result<Vec<String>, String> {
		self.retrieve_head(format!("HEAD\r\n").as_slice())
	}

	/// Retrieves the head of the article id.
	pub fn head_by_id(&mut self, article_id: &str) -> Result<Vec<String>, String> {
		self.retrieve_head(format!("HEAD {}\r\n", article_id).as_slice())
	}

	/// Retrieves the head of the article number in the currently selected newsgroup.
	pub fn head_by_number(&mut self, article_number: int) -> Result<Vec<String>, String> {
		self.retrieve_head(format!("HEAD {}\r\n", article_number).as_slice())
	}

	fn retrieve_head(&mut self, head_command: &str) -> Result<Vec<String>, String> {
		self.stream.write_str(head_command.as_slice());

		match self.read_response(221) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	/// Moves the currently selected article number back one
	pub fn last(&mut self) -> Result<String, String> {
		let last_command = format!("LAST\r\n");

		self.stream.write_str(last_command.as_slice());

		match self.read_response(223) {
			Ok((_, message)) => Ok(message),
			Err(e) => Err(e)
		}
	}

	/// Lists all of the newgroups on the server.
	pub fn list(&mut self) -> Result<Vec<String>, String> {
		let list_command = format!("LIST\r\n");

		self.stream.write_str(list_command.as_slice());

		match self.read_response(215) {
			Ok(_) => (),
			Err(e) => return Err(format!("{}", e))
		}

		self.read_multiline_response()
	}

	/// Selects a newsgroup
	pub fn group(&mut self, group: &str) -> Result<(), String> {
		let group_command = format!("GROUP {}\r\n", group);

		self.stream.write_str(group_command.as_slice());

		match self.read_response(211) {
			Ok(_) => Ok(()),
			Err(e) => Err(format!("{}", e))
		}
	}

	/// Show the help command given on the server.
	pub fn help(&mut self) -> Result<Vec<String>, String> {
		let help_command = format!("HELP\r\n");

		self.stream.write_str(help_command.as_slice());

		match self.read_response(100) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	/// Quits the current session.
	pub fn quit(&mut self) -> Result<(), String> {
		let quit_command = format!("QUIT\r\n");
		self.stream.write_str(quit_command.as_slice());

		match self.read_response(205) {
			Ok(_) => Ok(()),
			Err(e) => Err(format!("{}", e))
		}
	}

	/// Retrieves a list of newsgroups since the date and time given.
	pub fn newgroups(&mut self, date: &str, time: &str, use_gmt: bool) -> Result<Vec<String>, String> {
		let newgroups_command = match use_gmt {
			true => format!("NEWSGROUP {} {} GMT\r\n", date, time),
			false => format!("NEWSGROUP {} {}\r\n", date, time)
		};

		self.stream.write_str(newgroups_command.as_slice());

		match self.read_response(231) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	/// Retrieves a list of new news since the date and time given.
	pub fn newnews(&mut self, wildmat: &str, date: &str, time: &str, use_gmt: bool) -> Result<Vec<String>, String> {
		let newnews_command = match use_gmt {
			true => format!("NEWNEWS {} {} {} GMT\r\n", wildmat, date, time),
			false => format!("NEWNEWS {} {} {}\r\n", wildmat, date, time)
		};

		self.stream.write_str(newnews_command.as_slice());

		match self.read_response(230) {
			Ok(_) => (),
			Err(e) => return Err(e)
		}

		self.read_multiline_response()
	}

	/// Moves the currently selected article number forward one
	pub fn next(&mut self) -> Result<String, String> {
		let next_command = format!("NEXT\r\n");
		self.stream.write_str(next_command.as_slice());

		match self.read_response(223) {
			Ok((_, message)) => Ok(message),
			Err(e) => Err(e)
		}
	}

	/// Posts a message to the NNTP server.
	pub fn post(&mut self, message: &str) -> Result<(), String> {
		if !self.is_valid_message(message) {
			return Err(format!("Invalid message format. Message must end with \"\r\n.\r\n\""));
		}

		let post_command = format!("POST\r\n");

		self.stream.write_str(post_command.as_slice());

		match self.read_response(340) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		self.stream.write_str(message);

		match self.read_response(240) {
			Ok(_) => Ok(()),
			Err(e) => Err(e)
		}
	}

	/// Gets information about the current article.
	pub fn stat(&mut self) -> Result<String, String> {
		self.retrieve_stat(format!("STAT\r\n").as_slice())
	}

	/// Gets the information about the article id.
	pub fn stat_by_id(&mut self, article_id: &str) -> Result<String, String> {
		self.retrieve_stat(format!("STAT {}\r\n", article_id).as_slice())
	}

	/// Gets the information about the article number.
	pub fn stat_by_number(&mut self, article_number: int) -> Result<String, String> {
		self.retrieve_stat(format!("STAT {}\r\n", article_number).as_slice())
	}

	fn retrieve_stat(&mut self, stat_command: &str) -> Result<String, String> {
		self.stream.write_str(stat_command.as_slice());

		match self.read_response(223) {
			Ok((_, message)) => Ok(message),
			Err(e) => Err(e)
		}
	}

	fn is_valid_message(&mut self, message: &str) -> bool {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		//Dot
		let dot = 0x2e;
		let message_string = String::from_str(message);
		let message_bytes = message_string.as_bytes();
		let length = message_string.len();

		return length >= 5 && (message_bytes[length-1] == lf && message_bytes[length-2] == cr &&
			message_bytes[length-3] == dot && message_bytes[length-4] == lf && message_bytes[length-5] == cr)
	}

	//Retrieve single line response
	fn read_response(&mut self, expected_code: int) -> Result<(int, String), String> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut line_buffer: Vec<u8> = Vec::new();

		while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.stream.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => return Err(format!("Error reading response")),
				}
				line_buffer.push(byte_buffer[0]);
		}

		let response = String::from_utf8(line_buffer).unwrap();
		let chars_to_trim: &[char] = &['\r', '\n'];
		let trimmed_response = response.as_slice().trim_chars(chars_to_trim);
    	let trimmed_response_vec: Vec<char> = trimmed_response.chars().collect();
    	if trimmed_response_vec.len() < 5 || trimmed_response_vec[3] != ' ' {
    		return Err(format!("Invalid response"));
    	}

    	let v: Vec<&str> = trimmed_response.splitn(1, ' ').collect();
    	let code: int = from_str(v[0]).unwrap();
    	let message = v[1];
    	if code != expected_code {
    		return Err(format!("Invalid response: {} {}", code, message))
    	}
    	Ok((code, String::from_str(message)))
	}

	fn read_multiline_response(&mut self) -> Result<Vec<String>, String> {
		let mut response: Vec<String> = Vec::new();
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut line_buffer: Vec<u8> = Vec::new();
		let mut complete = false;

		while !complete {
			while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.stream.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => println!("Error Reading!"),
				}
				line_buffer.push(byte_buffer[0]);
			}

			match String::from_utf8(line_buffer.clone()) {
        		Ok(res) => {
        			if res == format!(".\r\n") {
        				complete = true;
        			}
        			else {
          				response.push(res.clone());
            			line_buffer = Vec::new();
            		}
        		},
        		Err(e) => return Err(format!("{}",e))
      		}
		}
		Ok(response)
	}
}<|endoftext|>


<commit_before>#![feature(macro_rules)]

#![crate_id="sdl2_image#sdl2_image:0.1"]
#![crate_type = "lib"]
#![desc = "SDL2_image bindings and wrappers"]
#![comment = "SDL2_image bindings and wrappers"]
#![license = "MIT"]

extern crate sdl2;
extern crate libc;

use libc::{c_int, c_char};
use std::ptr;
use sdl2::surface::Surface;
use sdl2::render::Texture;
use sdl2::render::Renderer;
use sdl2::rwops::RWops;
use sdl2::version::Version;
use sdl2::get_error;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(kind="framework", name="SDL2_image")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL2_image")]
    extern {}
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
mod others {
    #[link(name="SDL2_image")]
    extern {}
}

#[allow(non_camel_case_types, dead_code)]
mod ffi;
mod flag;

/// InitFlags are passed to init() to control which subsystem
/// functionality to load.
flag_type!(InitFlag : c_int {
    InitJpg = ffi::IMG_INIT_JPG,
    InitPng = ffi::IMG_INIT_PNG,
    InitTif = ffi::IMG_INIT_TIF,
    InitWebp = ffi::IMG_INIT_WEBP
})

/// Static method extensions for creating Surfaces
pub trait LoadSurface {
    // Self is only returned here to type hint to the compiler.
    // The syntax for type hinting in this case is not yet defined.
    // The intended return value is Result<~Surface, ~str>.
    fn from_file(filename: &Path) -> Result<~Self, ~str>;
    fn from_xpm_array(xpm: **i8) -> Result<~Self, ~str>;
}

/// Method extensions to Surface for saving to disk
pub trait SaveSurface {
    fn save(&self, filename: &Path) -> Result<(), ~str>;
    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str>;
}

impl LoadSurface for Surface {
    fn from_file(filename: &Path) -> Result<~Surface, ~str> {
        //! Loads an SDL Surface from a file
        unsafe {
            let raw = ffi::IMG_Load(filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Surface { raw: raw, owned: true })
            }
        }
    }

    fn from_xpm_array(xpm: **i8) -> Result<~Surface, ~str> {
        //! Loads an SDL Surface from XPM data
        unsafe {
            let raw = ffi::IMG_ReadXPMFromArray(xpm as **c_char);
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Surface { raw: raw, owned: true })
            }
        }
    }
}

impl SaveSurface for Surface {
    fn save(&self, filename: &Path) -> Result<(), ~str> {
        //! Saves an SDL Surface to a file
        unsafe {
            let status = ffi::IMG_SavePNG(self.raw,
                                          filename.to_c_str().unwrap());
            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }

    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str> {
        //! Saves an SDL Surface to an RWops
        unsafe {
            let status = ffi::IMG_SavePNG_RW(self.raw, dst.raw, 0);

            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Method extensions for creating Textures from a Renderer
pub trait LoadTexture {
    fn load_texture(&self, filename: &Path) -> Result<~Texture, ~str>;
}

impl LoadTexture for Renderer {
    fn load_texture(&self, filename: &Path) -> Result<~Texture, ~str> {
        //! Loads an SDL Texture from a file
        unsafe {
            let raw = ffi::IMG_LoadTexture(self.raw,
                                           filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(~Texture{ raw: raw, owned: true })
            }
        }
    }
}

pub fn init(flags: InitFlag) -> InitFlag {
    //! Initializes SDL2_image with InitFlags and returns which
    //! InitFlags were actually used.
    let used = unsafe { ffi::IMG_Init(flags.get()) };
    InitFlag::new(used)
}

pub fn quit() {
    //! Teardown the SDL2_Image subsystem
    unsafe { ffi::IMG_Quit(); }
}

pub fn get_linked_version() -> Version {
    //! Returns the version of the dynamically linked SDL_image library
    unsafe {
        Version::from_ll(ffi::IMG_Linked_Version())
    }
}

#[inline]
fn to_surface_result(raw: *sdl2::surface::ll::SDL_Surface) -> Result<~Surface, ~str> {
    if raw == ptr::null() {
        Err(get_error())
    } else {
        Ok(~Surface { raw: raw, owned: true })
    }
}

pub trait ImageRWops {
    /// load as a surface. except TGA
    fn load(&self) -> Result<~Surface, ~str>;
    /// load as a surface. This can load all supported image formats.
    fn load_typed(&self, _type: &str) -> Result<~Surface, ~str>;

    fn load_cur(&self) -> Result<~Surface, ~str>;
    fn load_ico(&self) -> Result<~Surface, ~str>;
    fn load_bmp(&self) -> Result<~Surface, ~str>;
    fn load_pnm(&self) -> Result<~Surface, ~str>;
    fn load_xpm(&self) -> Result<~Surface, ~str>;
    fn load_xcf(&self) -> Result<~Surface, ~str>;
    fn load_pcx(&self) -> Result<~Surface, ~str>;
    fn load_gif(&self) -> Result<~Surface, ~str>;
    fn load_jpg(&self) -> Result<~Surface, ~str>;
    fn load_tif(&self) -> Result<~Surface, ~str>;
    fn load_png(&self) -> Result<~Surface, ~str>;
    fn load_tga(&self) -> Result<~Surface, ~str>;
    fn load_lbm(&self) -> Result<~Surface, ~str>;
    fn load_xv(&self)  -> Result<~Surface, ~str>;
    fn load_webp(&self) -> Result<~Surface, ~str>;

    fn is_cur(&self) -> bool;
    fn is_ico(&self) -> bool;
    fn is_bmp(&self) -> bool;
    fn is_pnm(&self) -> bool;
    fn is_xpm(&self) -> bool;
    fn is_xcf(&self) -> bool;
    fn is_pcx(&self) -> bool;
    fn is_gif(&self) -> bool;
    fn is_jpg(&self) -> bool;
    fn is_tif(&self) -> bool;
    fn is_png(&self) -> bool;
    fn is_lbm(&self) -> bool;
    fn is_xv(&self)  -> bool;
    fn is_webp(&self) -> bool;
}

impl ImageRWops for RWops {
    fn load(&self) -> Result<~Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_Load_RW(self.raw, 0)
        };
        to_surface_result(raw)
    }
    fn load_typed(&self, _type: &str) -> Result<~Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_LoadTyped_RW(self.raw, 0, _type.to_c_str().unwrap())
        };
        to_surface_result(raw)
    }

    fn load_cur(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadCUR_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_ico(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadICO_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_bmp(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadBMP_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pnm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xpm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXPM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xcf(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXCF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pcx(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPCX_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_gif(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadGIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_jpg(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadJPG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tif(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_png(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tga(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTGA_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_lbm(&self) -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadLBM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xv(&self)  -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXV_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_webp(&self)  -> Result<~Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadWEBP_RW(self.raw) };
        to_surface_result(raw)
    }

    fn is_cur(&self) -> bool {
        unsafe { ffi::IMG_isCUR(self.raw) == 1 }
    }
    fn is_ico(&self) -> bool {
        unsafe { ffi::IMG_isICO(self.raw) == 1 }
    }
    fn is_bmp(&self) -> bool {
        unsafe { ffi::IMG_isBMP(self.raw) == 1 }
    }
    fn is_pnm(&self) -> bool {
        unsafe { ffi::IMG_isPNM(self.raw) == 1 }
    }
    fn is_xpm(&self) -> bool {
        unsafe { ffi::IMG_isXPM(self.raw) == 1 }
    }
    fn is_xcf(&self) -> bool {
        unsafe { ffi::IMG_isXCF(self.raw) == 1 }
    }
    fn is_pcx(&self) -> bool {
        unsafe { ffi::IMG_isPCX(self.raw) == 1 }
    }
    fn is_gif(&self) -> bool {
        unsafe { ffi::IMG_isGIF(self.raw) == 1 }
    }
    fn is_jpg(&self) -> bool {
        unsafe { ffi::IMG_isJPG(self.raw) == 1 }
    }
    fn is_tif(&self) -> bool {
        unsafe { ffi::IMG_isTIF(self.raw) == 1 }
    }
    fn is_png(&self) -> bool {
        unsafe { ffi::IMG_isPNG(self.raw) == 1 }
    }
    fn is_lbm(&self) -> bool {
        unsafe { ffi::IMG_isLBM(self.raw) == 1 }
    }
    fn is_xv(&self)  -> bool {
        unsafe { ffi::IMG_isXV(self.raw)  == 1 }
    }
    fn is_webp(&self) -> bool {
        unsafe { ffi::IMG_isWEBP(self.raw)  == 1 }
    }
}
<commit_msg>use unboxed return type<commit_after>#![feature(macro_rules)]

#![crate_id="sdl2_image#sdl2_image:0.1"]
#![crate_type = "lib"]
#![desc = "SDL2_image bindings and wrappers"]
#![comment = "SDL2_image bindings and wrappers"]
#![license = "MIT"]

extern crate sdl2;
extern crate libc;

use libc::{c_int, c_char};
use std::ptr;
use sdl2::surface::Surface;
use sdl2::render::Texture;
use sdl2::render::Renderer;
use sdl2::rwops::RWops;
use sdl2::version::Version;
use sdl2::get_error;

// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link(kind="framework", name="SDL2_image")]
    extern {}

    #[cfg(not(mac_framework))]
    #[link(name="SDL2_image")]
    extern {}
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
mod others {
    #[link(name="SDL2_image")]
    extern {}
}

#[allow(non_camel_case_types, dead_code)]
mod ffi;
mod flag;

/// InitFlags are passed to init() to control which subsystem
/// functionality to load.
flag_type!(InitFlag : c_int {
    InitJpg = ffi::IMG_INIT_JPG,
    InitPng = ffi::IMG_INIT_PNG,
    InitTif = ffi::IMG_INIT_TIF,
    InitWebp = ffi::IMG_INIT_WEBP
})

/// Static method extensions for creating Surfaces
pub trait LoadSurface {
    // Self is only returned here to type hint to the compiler.
    // The syntax for type hinting in this case is not yet defined.
    // The intended return value is Result<~Surface, ~str>.
    fn from_file(filename: &Path) -> Result<Self, ~str>;
    fn from_xpm_array(xpm: **i8) -> Result<Self, ~str>;
}

/// Method extensions to Surface for saving to disk
pub trait SaveSurface {
    fn save(&self, filename: &Path) -> Result<(), ~str>;
    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str>;
}

impl LoadSurface for Surface {
    fn from_file(filename: &Path) -> Result<Surface, ~str> {
        //! Loads an SDL Surface from a file
        unsafe {
            let raw = ffi::IMG_Load(filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Surface { raw: raw, owned: true })
            }
        }
    }

    fn from_xpm_array(xpm: **i8) -> Result<Surface, ~str> {
        //! Loads an SDL Surface from XPM data
        unsafe {
            let raw = ffi::IMG_ReadXPMFromArray(xpm as **c_char);
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Surface { raw: raw, owned: true })
            }
        }
    }
}

impl SaveSurface for Surface {
    fn save(&self, filename: &Path) -> Result<(), ~str> {
        //! Saves an SDL Surface to a file
        unsafe {
            let status = ffi::IMG_SavePNG(self.raw,
                                          filename.to_c_str().unwrap());
            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }

    fn save_rw(&self, dst: &mut RWops) -> Result<(), ~str> {
        //! Saves an SDL Surface to an RWops
        unsafe {
            let status = ffi::IMG_SavePNG_RW(self.raw, dst.raw, 0);

            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Method extensions for creating Textures from a Renderer
pub trait LoadTexture {
    fn load_texture(&self, filename: &Path) -> Result<Texture, ~str>;
}

impl LoadTexture for Renderer {
    fn load_texture(&self, filename: &Path) -> Result<Texture, ~str> {
        //! Loads an SDL Texture from a file
        unsafe {
            let raw = ffi::IMG_LoadTexture(self.raw,
                                           filename.to_c_str().unwrap());
            if raw == ptr::null() {
                Err(get_error())
            } else {
                Ok(Texture{ raw: raw, owned: true })
            }
        }
    }
}

pub fn init(flags: InitFlag) -> InitFlag {
    //! Initializes SDL2_image with InitFlags and returns which
    //! InitFlags were actually used.
    let used = unsafe { ffi::IMG_Init(flags.get()) };
    InitFlag::new(used)
}

pub fn quit() {
    //! Teardown the SDL2_Image subsystem
    unsafe { ffi::IMG_Quit(); }
}

pub fn get_linked_version() -> Version {
    //! Returns the version of the dynamically linked SDL_image library
    unsafe {
        Version::from_ll(ffi::IMG_Linked_Version())
    }
}

#[inline]
fn to_surface_result(raw: *sdl2::surface::ll::SDL_Surface) -> Result<Surface, ~str> {
    if raw == ptr::null() {
        Err(get_error())
    } else {
        Ok(Surface { raw: raw, owned: true })
    }
}

pub trait ImageRWops {
    /// load as a surface. except TGA
    fn load(&self) -> Result<Surface, ~str>;
    /// load as a surface. This can load all supported image formats.
    fn load_typed(&self, _type: &str) -> Result<Surface, ~str>;

    fn load_cur(&self) -> Result<Surface, ~str>;
    fn load_ico(&self) -> Result<Surface, ~str>;
    fn load_bmp(&self) -> Result<Surface, ~str>;
    fn load_pnm(&self) -> Result<Surface, ~str>;
    fn load_xpm(&self) -> Result<Surface, ~str>;
    fn load_xcf(&self) -> Result<Surface, ~str>;
    fn load_pcx(&self) -> Result<Surface, ~str>;
    fn load_gif(&self) -> Result<Surface, ~str>;
    fn load_jpg(&self) -> Result<Surface, ~str>;
    fn load_tif(&self) -> Result<Surface, ~str>;
    fn load_png(&self) -> Result<Surface, ~str>;
    fn load_tga(&self) -> Result<Surface, ~str>;
    fn load_lbm(&self) -> Result<Surface, ~str>;
    fn load_xv(&self)  -> Result<Surface, ~str>;
    fn load_webp(&self) -> Result<Surface, ~str>;

    fn is_cur(&self) -> bool;
    fn is_ico(&self) -> bool;
    fn is_bmp(&self) -> bool;
    fn is_pnm(&self) -> bool;
    fn is_xpm(&self) -> bool;
    fn is_xcf(&self) -> bool;
    fn is_pcx(&self) -> bool;
    fn is_gif(&self) -> bool;
    fn is_jpg(&self) -> bool;
    fn is_tif(&self) -> bool;
    fn is_png(&self) -> bool;
    fn is_lbm(&self) -> bool;
    fn is_xv(&self)  -> bool;
    fn is_webp(&self) -> bool;
}

impl ImageRWops for RWops {
    fn load(&self) -> Result<Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_Load_RW(self.raw, 0)
        };
        to_surface_result(raw)
    }
    fn load_typed(&self, _type: &str) -> Result<Surface, ~str> {
        let raw = unsafe {
            ffi::IMG_LoadTyped_RW(self.raw, 0, _type.to_c_str().unwrap())
        };
        to_surface_result(raw)
    }

    fn load_cur(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadCUR_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_ico(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadICO_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_bmp(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadBMP_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pnm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xpm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXPM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xcf(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXCF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_pcx(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPCX_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_gif(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadGIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_jpg(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadJPG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tif(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTIF_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_png(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadPNG_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_tga(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadTGA_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_lbm(&self) -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadLBM_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_xv(&self)  -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadXV_RW(self.raw) };
        to_surface_result(raw)
    }
    fn load_webp(&self)  -> Result<Surface, ~str> {
        let raw = unsafe { ffi::IMG_LoadWEBP_RW(self.raw) };
        to_surface_result(raw)
    }

    fn is_cur(&self) -> bool {
        unsafe { ffi::IMG_isCUR(self.raw) == 1 }
    }
    fn is_ico(&self) -> bool {
        unsafe { ffi::IMG_isICO(self.raw) == 1 }
    }
    fn is_bmp(&self) -> bool {
        unsafe { ffi::IMG_isBMP(self.raw) == 1 }
    }
    fn is_pnm(&self) -> bool {
        unsafe { ffi::IMG_isPNM(self.raw) == 1 }
    }
    fn is_xpm(&self) -> bool {
        unsafe { ffi::IMG_isXPM(self.raw) == 1 }
    }
    fn is_xcf(&self) -> bool {
        unsafe { ffi::IMG_isXCF(self.raw) == 1 }
    }
    fn is_pcx(&self) -> bool {
        unsafe { ffi::IMG_isPCX(self.raw) == 1 }
    }
    fn is_gif(&self) -> bool {
        unsafe { ffi::IMG_isGIF(self.raw) == 1 }
    }
    fn is_jpg(&self) -> bool {
        unsafe { ffi::IMG_isJPG(self.raw) == 1 }
    }
    fn is_tif(&self) -> bool {
        unsafe { ffi::IMG_isTIF(self.raw) == 1 }
    }
    fn is_png(&self) -> bool {
        unsafe { ffi::IMG_isPNG(self.raw) == 1 }
    }
    fn is_lbm(&self) -> bool {
        unsafe { ffi::IMG_isLBM(self.raw) == 1 }
    }
    fn is_xv(&self)  -> bool {
        unsafe { ffi::IMG_isXV(self.raw)  == 1 }
    }
    fn is_webp(&self) -> bool {
        unsafe { ffi::IMG_isWEBP(self.raw)  == 1 }
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is natural number, position is (min, max).
pub struct Pair<T = Data>(PhantomData<T>);

impl<T> Construct for Pair<T> {
    fn new() -> Pair<T> { Pair(PhantomData) }
}

impl Count<usize> for Pair<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize { dim * (dim - 1) / 2 }
}

impl<T, U> Count<U> for Pair<Of<T>>
    where
        T: Construct + Count<U, N = usize>
{
    type N = usize;
    fn count(&self, dim: &U) -> usize {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        data.count(&of.count(dim))
    }
}

impl Zero<usize, (usize, usize)> for Pair<Data> {
    fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) }
}

impl<T, U, V>
Zero<U, (V, V)> for Pair<Of<T>>
    where T: Construct + Zero<U, V>
{
    fn zero(&self, dim: &U) -> (V, V) {
        let of: T = Construct::new();
        (of.zero(dim), of.zero(dim))
    }
}

impl ToIndex<usize, (usize, usize)>
for Pair<Data> {
    fn to_index(&self, _dim: &usize, &(min, max): &(usize, usize)) -> usize {
        min + max * (max - 1) / 2
    }
}

impl<T, U, V>
ToIndex<U, (V, V)> for Pair<Of<T>>
    where T: Construct + ToIndex<U, V> + Count<U, N = usize>
{
    fn to_index(
        &self,
        dim: &U,
        &(ref min, ref max): &(V, V)
    ) -> usize {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        let min = of.to_index(dim, min);
        let max = of.to_index(dim, max);
        data.to_index(&self.count(dim), &(min, max))
    }
}

impl ToPos<usize, (usize, usize)> for Pair<Data> {
    fn to_pos(&self, _dim: &usize, index: usize, pos: &mut (usize, usize)) {
        let max = ((-1f64 + (8f64 * index as f64 + 1f64).sqrt()) / 2f64) as usize + 1;
        let min = index.wrapping_sub(max * (max + 1) / 2).wrapping_add(max);
        *pos = (min, max)
    }
}

impl<T, U, V>
ToPos<U, (V, V)> for Pair<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        &mut (ref mut min, ref mut max): &mut (V, V)
    ) {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        let count = of.count(dim);
        let mut pair = (0, 0);
        data.to_pos(&count, index, &mut pair);
        let (pair_min, pair_max) = pair;
        of.to_pos(dim, pair_min, min);
        of.to_pos(dim, pair_max, max);
    }
}

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

    #[test]
    fn features() {
        is_complete::<Pair, usize, (usize, usize)>();
        is_complete::<Pair<Of<Pair>>, usize,
            ((usize, usize), (usize, usize))>();
    }

    #[test]
    fn data() {
        let x: Pair = Construct::new();
        let ref dim = 4;
        assert_eq!(x.count(dim), 6);
        assert_eq!(x.to_index(dim, &(0, 1)), 0);
        assert_eq!(x.to_index(dim, &(0, 2)), 1);
        assert_eq!(x.to_index(dim, &(1, 2)), 2);
        assert_eq!(x.to_index(dim, &(0, 3)), 3);
        let mut new_pos = (0, 0);
        x.to_pos(dim, 3, &mut new_pos);
        assert_eq!(new_pos, (0, 3));
    }

    #[test]
    fn of() {
        let x: Pair<Of<DimensionN>> = Construct::new();
        let ref dim = vec![2, 2];
        assert_eq!(x.count(dim), 6);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 0])), 0);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![0, 1])), 1);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![0, 1])), 2);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 1])), 3);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![1, 1])), 4);
        assert_eq!(x.to_index(dim, &(vec![0, 1], vec![1, 1])), 5);
        let mut pos = (Vec::new(), Vec::new());
        for i in 0..6 {
            x.to_pos(dim, i, &mut pos);
            // println!("{} {}", &min[], &max[]);
        }
        x.to_pos(dim, 5, &mut pos);
        assert_eq!(&pos.0, &[0, 1]);
        assert_eq!(&pos.1, &[1, 1]);
    }
}
<commit_msg>Impl `Count<BigUint>` for `Pair`<commit_after>use std::marker::PhantomData;

use num::BigUint;

use Construct;
use Data;
use Count;
use Of;
use ToIndex;
use ToPos;
use Zero;

/// Dimension is natural number, position is (min, max).
pub struct Pair<T = Data>(PhantomData<T>);

impl<T> Construct for Pair<T> {
    fn new() -> Pair<T> { Pair(PhantomData) }
}

impl Count<usize> for Pair<Data> {
    type N = usize;
    fn count(&self, dim: &usize) -> usize { dim * (dim - 1) / 2 }
}

impl Count<BigUint> for Pair<Data> {
    type N = BigUint;
    fn count(&self, dim: &BigUint) -> BigUint {
        let _1: BigUint = 1usize.into();
        let _2: BigUint = 2usize.into();
        dim * (dim - _1) / _2
    }
}

impl<T, U> Count<U> for Pair<Of<T>>
    where
        T: Construct + Count<U>,
        Pair: Count<<T as Count<U>>::N, N = <T as Count<U>>::N>
{
    type N = <T as Count<U>>::N;
    fn count(&self, dim: &U) -> Self::N {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        data.count(&of.count(dim))
    }
}

impl Zero<usize, (usize, usize)> for Pair<Data> {
    fn zero(&self, _dim: &usize) -> (usize, usize) { (0, 0) }
}

impl<T, U, V>
Zero<U, (V, V)> for Pair<Of<T>>
    where T: Construct + Zero<U, V>
{
    fn zero(&self, dim: &U) -> (V, V) {
        let of: T = Construct::new();
        (of.zero(dim), of.zero(dim))
    }
}

impl ToIndex<usize, (usize, usize)>
for Pair<Data> {
    fn to_index(&self, _dim: &usize, &(min, max): &(usize, usize)) -> usize {
        min + max * (max - 1) / 2
    }
}

impl<T, U, V>
ToIndex<U, (V, V)> for Pair<Of<T>>
    where T: Construct + ToIndex<U, V> + Count<U, N = usize>
{
    fn to_index(
        &self,
        dim: &U,
        &(ref min, ref max): &(V, V)
    ) -> usize {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        let min = of.to_index(dim, min);
        let max = of.to_index(dim, max);
        data.to_index(&self.count(dim), &(min, max))
    }
}

impl ToPos<usize, (usize, usize)> for Pair<Data> {
    fn to_pos(&self, _dim: &usize, index: usize, pos: &mut (usize, usize)) {
        let max = ((-1f64 + (8f64 * index as f64 + 1f64).sqrt()) / 2f64) as usize + 1;
        let min = index.wrapping_sub(max * (max + 1) / 2).wrapping_add(max);
        *pos = (min, max)
    }
}

impl<T, U, V>
ToPos<U, (V, V)> for Pair<Of<T>>
    where T: Construct + Count<U, N = usize> + ToPos<U, V>
{
    fn to_pos(
        &self,
        dim: &U,
        index: usize,
        &mut (ref mut min, ref mut max): &mut (V, V)
    ) {
        let of: T = Construct::new();
        let data: Pair<Data> = Construct::new();
        let count = of.count(dim);
        let mut pair = (0, 0);
        data.to_pos(&count, index, &mut pair);
        let (pair_min, pair_max) = pair;
        of.to_pos(dim, pair_min, min);
        of.to_pos(dim, pair_max, max);
    }
}

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

    #[test]
    fn features() {
        is_complete::<Pair, usize, (usize, usize)>();
        is_complete::<Pair<Of<Pair>>, usize,
            ((usize, usize), (usize, usize))>();
    }

    #[test]
    fn data() {
        let x: Pair = Construct::new();
        let ref dim = 4;
        assert_eq!(x.count(dim), 6);
        assert_eq!(x.to_index(dim, &(0, 1)), 0);
        assert_eq!(x.to_index(dim, &(0, 2)), 1);
        assert_eq!(x.to_index(dim, &(1, 2)), 2);
        assert_eq!(x.to_index(dim, &(0, 3)), 3);
        let mut new_pos = (0, 0);
        x.to_pos(dim, 3, &mut new_pos);
        assert_eq!(new_pos, (0, 3));
    }

    #[test]
    fn of() {
        let x: Pair<Of<DimensionN>> = Construct::new();
        let ref dim = vec![2, 2];
        assert_eq!(x.count(dim), 6);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 0])), 0);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![0, 1])), 1);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![0, 1])), 2);
        assert_eq!(x.to_index(dim, &(vec![0, 0], vec![1, 1])), 3);
        assert_eq!(x.to_index(dim, &(vec![1, 0], vec![1, 1])), 4);
        assert_eq!(x.to_index(dim, &(vec![0, 1], vec![1, 1])), 5);
        let mut pos = (Vec::new(), Vec::new());
        for i in 0..6 {
            x.to_pos(dim, i, &mut pos);
            // println!("{} {}", &min[], &max[]);
        }
        x.to_pos(dim, 5, &mut pos);
        assert_eq!(&pos.0, &[0, 1]);
        assert_eq!(&pos.1, &[1, 1]);
    }
}
<|endoftext|>


<commit_before>
use ffi;
use super::enums::*;
use super::raw_vec::RawVec;
use super::util::FFTW_MUTEX;
use super::{c32, c64};

use std::marker::PhantomData;

pub struct Plan<A, B> {
    plan: RawPlan,
    phantom: PhantomData<(A, B)>,
}

impl<A, B> Plan<A, B> {
    /// this function modifys the array referred in plan creation
    pub unsafe fn execute(&self) { self.plan.execute() }
}

impl<T: R2RPlanCreate> Plan<T, T> {
    pub fn r2r_1d(n: usize,
                  mut in_: &mut RawVec<T>,
                  mut out: &mut RawVec<T>,
                  kind: R2R_KIND,
                  flag: FLAG)
                  -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let plan = unsafe { T::r2r_1d(n, &mut in_, &mut out, kind, flag) };
        drop(lock);
        Plan {
            plan: plan,
            phantom: PhantomData,
        }
    }
}

impl<T: C2CPlanCreate> Plan<T, T> {
    pub fn c2c_1d(n: usize,
                  mut in_: &mut RawVec<T>,
                  mut out: &mut RawVec<T>,
                  sign: SIGN,
                  flag: FLAG)
                  -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let plan = unsafe { T::c2c_1d(n, &mut in_, &mut out, sign, flag) };
        drop(lock);
        Plan {
            plan: plan,
            phantom: PhantomData,
        }
    }
}

impl<C, R> Plan<C, R>
    where (C, R): C2RPlanCreate<Real = R, Complex = C>
{
    pub fn c2r_1d(n: usize, in_: &mut RawVec<C>, out: &mut RawVec<R>, flag: FLAG) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let plan = unsafe { <(C, R)>::c2r_1d(n, in_, out, flag) };
        drop(lock);
        Plan {
            plan: plan,
            phantom: PhantomData,
        }
    }
}

impl<R, C> Plan<R, C>
    where (C, R): C2RPlanCreate<Real = R, Complex = C>
{
    pub fn r2c_1d(n: usize, in_: &mut RawVec<R>, out: &mut RawVec<C>, flag: FLAG) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let plan = unsafe { <(C, R)>::r2c_1d(n, in_, out, flag) };
        drop(lock);
        Plan {
            plan: plan,
            phantom: PhantomData,
        }
    }
}

pub enum RawPlan {
    _64(ffi::fftw_plan),
    _32(ffi::fftwf_plan),
}

impl RawPlan {
    pub unsafe fn execute(&self) {
        match *self {
            RawPlan::_64(p) => ffi::fftw_execute(p),
            RawPlan::_32(p) => ffi::fftwf_execute(p),
        }
    }
}

impl Drop for RawPlan {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe {
            match *self {
                RawPlan::_64(p) => ffi::fftw_destroy_plan(p),
                RawPlan::_32(p) => ffi::fftwf_destroy_plan(p),
            }
        }
        drop(lock);
    }
}

pub trait R2RPlanCreate: Sized {
    unsafe fn r2r_1d(n: usize,
                     in_: &mut RawVec<Self>,
                     out: &mut RawVec<Self>,
                     R2R_KIND,
                     FLAG)
                     -> RawPlan;
}
pub trait C2CPlanCreate: Sized {
    unsafe fn c2c_1d(n: usize,
                     in_: &mut RawVec<Self>,
                     out: &mut RawVec<Self>,
                     SIGN,
                     FLAG)
                     -> RawPlan;
}

pub trait C2RPlanCreate {
    type Real: Sized;
    type Complex: Sized;
    unsafe fn r2c_1d(n: usize,
                     in_: &mut RawVec<Self::Real>,
                     out: &mut RawVec<Self::Complex>,
                     FLAG)
                     -> RawPlan;
    unsafe fn c2r_1d(n: usize,
                     in_: &mut RawVec<Self::Complex>,
                     out: &mut RawVec<Self::Real>,
                     FLAG)
                     -> RawPlan;
}

macro_rules! impl_plan_create {
    ($bit:ident, $float:ty, $complex:ty,
     $r2r_1d:ident, $r2c_1d:ident, $c2r_1d:ident, $c2c_1d:ident) => {

impl R2RPlanCreate for $float {
    unsafe fn r2r_1d(n: usize, in_: &mut RawVec<Self>, out: &mut RawVec<Self>, kind: R2R_KIND, flag: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$r2r_1d(n as i32, in_.as_mut_ptr(), out.as_mut_ptr(), kind, flag as u32))
    }
}

impl C2CPlanCreate for $complex {
    unsafe fn c2c_1d(n: usize, i: &mut RawVec<Self>, o: &mut RawVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$c2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
}

impl C2RPlanCreate for ($complex, $float) {
    type Real = $float;
    type Complex = $complex;
    unsafe fn r2c_1d(n: usize, i: &mut RawVec<Self::Real>, o: &mut RawVec<Self::Complex>, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$r2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_1d(n: usize, i: &mut RawVec<Self::Complex>, o: &mut RawVec<Self::Real>, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$c2r_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
}

}} // impl_plan_create

impl_plan_create!(_64,
                  f64,
                  c64,
                  fftw_plan_r2r_1d,
                  fftw_plan_dft_r2c_1d,
                  fftw_plan_dft_c2r_1d,
                  fftw_plan_dft_1d);
impl_plan_create!(_32,
                  f32,
                  c32,
                  fftwf_plan_r2r_1d,
                  fftwf_plan_dft_r2c_1d,
                  fftwf_plan_dft_c2r_1d,
                  fftwf_plan_dft_1d);
<commit_msg>Support 2d/3d in *PlanCreate<commit_after>
use ffi;
use super::enums::*;
use super::raw_vec::RawVec;
use super::util::FFTW_MUTEX;
use super::{c32, c64};

use std::marker::PhantomData;

pub struct Plan<A, B> {
    plan: RawPlan,
    phantom: PhantomData<(A, B)>,
}

impl<A, B> Plan<A, B> {
    /// this function modifys the array referred in plan creation
    pub unsafe fn execute(&self) { self.plan.execute() }
}

impl<T: R2RPlanCreate> Plan<T, T> {
    pub fn r2r_1d(n: usize,
                  mut in_: &mut RawVec<T>,
                  mut out: &mut RawVec<T>,
                  kind: R2R_KIND,
                  flag: FLAG)
                  -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let plan = unsafe { T::r2r_1d(n, &mut in_, &mut out, kind, flag) };
        drop(lock);
        Plan {
            plan: plan,
            phantom: PhantomData,
        }
    }
}

impl<T: C2CPlanCreate> Plan<T, T> {
    pub fn c2c_1d(n: usize,
                  mut in_: &mut RawVec<T>,
                  mut out: &mut RawVec<T>,
                  sign: SIGN,
                  flag: FLAG)
                  -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let plan = unsafe { T::c2c_1d(n, &mut in_, &mut out, sign, flag) };
        drop(lock);
        Plan {
            plan: plan,
            phantom: PhantomData,
        }
    }
}

impl<C, R> Plan<C, R>
    where (C, R): C2RPlanCreate<Real = R, Complex = C>
{
    pub fn c2r_1d(n: usize, in_: &mut RawVec<C>, out: &mut RawVec<R>, flag: FLAG) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let plan = unsafe { <(C, R)>::c2r_1d(n, in_, out, flag) };
        drop(lock);
        Plan {
            plan: plan,
            phantom: PhantomData,
        }
    }
}

impl<R, C> Plan<R, C>
    where (C, R): C2RPlanCreate<Real = R, Complex = C>
{
    pub fn r2c_1d(n: usize, in_: &mut RawVec<R>, out: &mut RawVec<C>, flag: FLAG) -> Self {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        let plan = unsafe { <(C, R)>::r2c_1d(n, in_, out, flag) };
        drop(lock);
        Plan {
            plan: plan,
            phantom: PhantomData,
        }
    }
}

pub enum RawPlan {
    _64(ffi::fftw_plan),
    _32(ffi::fftwf_plan),
}

impl RawPlan {
    pub unsafe fn execute(&self) {
        match *self {
            RawPlan::_64(p) => ffi::fftw_execute(p),
            RawPlan::_32(p) => ffi::fftwf_execute(p),
        }
    }
}

impl Drop for RawPlan {
    fn drop(&mut self) {
        let lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe {
            match *self {
                RawPlan::_64(p) => ffi::fftw_destroy_plan(p),
                RawPlan::_32(p) => ffi::fftwf_destroy_plan(p),
            }
        }
        drop(lock);
    }
}

pub trait R2RPlanCreate: Sized {
    unsafe fn r2r_1d(n: usize,
                     in_: &mut RawVec<Self>,
                     out: &mut RawVec<Self>,
                     R2R_KIND,
                     FLAG)
                     -> RawPlan;
    unsafe fn r2r_2d(n0: usize,
                     n1: usize,
                     in_: &mut RawVec<Self>,
                     out: &mut RawVec<Self>,
                     R2R_KIND,
                     R2R_KIND,
                     FLAG)
                     -> RawPlan;
    unsafe fn r2r_3d(n0: usize,
                     n1: usize,
                     n2: usize,
                     in_: &mut RawVec<Self>,
                     out: &mut RawVec<Self>,
                     R2R_KIND,
                     R2R_KIND,
                     R2R_KIND,
                     FLAG)
                     -> RawPlan;
}
pub trait C2CPlanCreate: Sized {
    unsafe fn c2c_1d(n: usize,
                     in_: &mut RawVec<Self>,
                     out: &mut RawVec<Self>,
                     SIGN,
                     FLAG)
                     -> RawPlan;
    unsafe fn c2c_2d(n0: usize,
                     n1: usize,
                     in_: &mut RawVec<Self>,
                     out: &mut RawVec<Self>,
                     SIGN,
                     FLAG)
                     -> RawPlan;
    unsafe fn c2c_3d(n0: usize,
                     n1: usize,
                     n2: usize,
                     in_: &mut RawVec<Self>,
                     out: &mut RawVec<Self>,
                     SIGN,
                     FLAG)
                     -> RawPlan;
}

pub trait C2RPlanCreate {
    type Real: Sized;
    type Complex: Sized;
    unsafe fn r2c_1d(n: usize,
                     in_: &mut RawVec<Self::Real>,
                     out: &mut RawVec<Self::Complex>,
                     FLAG)
                     -> RawPlan;
    unsafe fn c2r_1d(n: usize,
                     in_: &mut RawVec<Self::Complex>,
                     out: &mut RawVec<Self::Real>,
                     FLAG)
                     -> RawPlan;
    unsafe fn r2c_2d(n0: usize,
                     n1: usize,
                     in_: &mut RawVec<Self::Real>,
                     out: &mut RawVec<Self::Complex>,
                     FLAG)
                     -> RawPlan;
    unsafe fn c2r_2d(n0: usize,
                     n1: usize,
                     in_: &mut RawVec<Self::Complex>,
                     out: &mut RawVec<Self::Real>,
                     FLAG)
                     -> RawPlan;
    unsafe fn r2c_3d(n0: usize,
                     n1: usize,
                     n2: usize,
                     in_: &mut RawVec<Self::Real>,
                     out: &mut RawVec<Self::Complex>,
                     FLAG)
                     -> RawPlan;
    unsafe fn c2r_3d(n0: usize,
                     n1: usize,
                     n2: usize,
                     in_: &mut RawVec<Self::Complex>,
                     out: &mut RawVec<Self::Real>,
                     FLAG)
                     -> RawPlan;
}

macro_rules! impl_plan_create {
    ($bit:ident, $float:ty, $complex:ty,
     $r2r_1d:ident, $r2c_1d:ident, $c2r_1d:ident, $c2c_1d:ident,
     $r2r_2d:ident, $r2c_2d:ident, $c2r_2d:ident, $c2c_2d:ident,
     $r2r_3d:ident, $r2c_3d:ident, $c2r_3d:ident, $c2c_3d:ident) => {

impl R2RPlanCreate for $float {
    unsafe fn r2r_1d(n: usize, in_: &mut RawVec<Self>, out: &mut RawVec<Self>, kind: R2R_KIND, flag: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$r2r_1d(n as i32, in_.as_mut_ptr(), out.as_mut_ptr(), kind, flag as u32))
    }
    unsafe fn r2r_2d(n0: usize, n1: usize, in_: &mut RawVec<Self>, out: &mut RawVec<Self>, k0: R2R_KIND, k1: R2R_KIND, flag: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$r2r_2d(n0 as i32, n1 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, flag as u32))
    }
    unsafe fn r2r_3d(n0: usize, n1: usize, n2: usize, in_: &mut RawVec<Self>, out: &mut RawVec<Self>, k0: R2R_KIND, k1: R2R_KIND, k2: R2R_KIND, flag: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$r2r_3d(n0 as i32, n1 as i32, n2 as i32, in_.as_mut_ptr(), out.as_mut_ptr(), k0, k1, k2, flag as u32))
    }
}

impl C2CPlanCreate for $complex {
    unsafe fn c2c_1d(n: usize, i: &mut RawVec<Self>, o: &mut RawVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$c2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_2d(n0: usize, n1: usize, i: &mut RawVec<Self>, o: &mut RawVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$c2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
    unsafe fn c2c_3d(n0: usize, n1: usize, n2: usize, i: &mut RawVec<Self>, o: &mut RawVec<Self>, s: SIGN, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$c2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), s as i32, f as u32))
    }
}

impl C2RPlanCreate for ($complex, $float) {
    type Real = $float;
    type Complex = $complex;
    unsafe fn r2c_1d(n: usize, i: &mut RawVec<Self::Real>, o: &mut RawVec<Self::Complex>, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$r2c_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_1d(n: usize, i: &mut RawVec<Self::Complex>, o: &mut RawVec<Self::Real>, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$c2r_1d(n as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_2d(n0: usize, n1: usize, i: &mut RawVec<Self::Real>, o: &mut RawVec<Self::Complex>, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$r2c_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_2d(n0: usize, n1: usize, i: &mut RawVec<Self::Complex>, o: &mut RawVec<Self::Real>, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$c2r_2d(n0 as i32, n1 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn r2c_3d(n0: usize, n1: usize, n2: usize, i: &mut RawVec<Self::Real>, o: &mut RawVec<Self::Complex>, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$r2c_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
    unsafe fn c2r_3d(n0: usize, n1: usize, n2: usize, i: &mut RawVec<Self::Complex>, o: &mut RawVec<Self::Real>, f: FLAG) -> RawPlan {
        RawPlan::$bit(ffi::$c2r_3d(n0 as i32, n1 as i32, n2 as i32, i.as_mut_ptr(), o.as_mut_ptr(), f as u32))
    }
}

}} // impl_plan_create

impl_plan_create!(_64,
                  f64,
                  c64,
                  fftw_plan_r2r_1d,
                  fftw_plan_dft_r2c_1d,
                  fftw_plan_dft_c2r_1d,
                  fftw_plan_dft_1d,
                  fftw_plan_r2r_2d,
                  fftw_plan_dft_r2c_2d,
                  fftw_plan_dft_c2r_2d,
                  fftw_plan_dft_2d,
                  fftw_plan_r2r_3d,
                  fftw_plan_dft_r2c_3d,
                  fftw_plan_dft_c2r_3d,
                  fftw_plan_dft_3d);
impl_plan_create!(_32,
                  f32,
                  c32,
                  fftwf_plan_r2r_1d,
                  fftwf_plan_dft_r2c_1d,
                  fftwf_plan_dft_c2r_1d,
                  fftwf_plan_dft_1d,
                  fftwf_plan_r2r_2d,
                  fftwf_plan_dft_r2c_2d,
                  fftwf_plan_dft_c2r_2d,
                  fftwf_plan_dft_2d,
                  fftwf_plan_r2r_3d,
                  fftwf_plan_dft_r2c_3d,
                  fftwf_plan_dft_c2r_3d,
                  fftwf_plan_dft_3d);
<|endoftext|>