<commit_before>use std::io;
use std::io::prelude::*;
use std::fs::{self, File, ReadDir, DirEntry};
use std::path::Path;
use std::vec;
use std::io::BufReader;
use std::cmp::Ordering;
use std::str::FromStr;

/// Get process stats (/proc/[pid]/stat)
mod stat;
/// Get process status (/proc/[pid]/status)
mod status;

use self::stat::PidStat;
use self::status::PidStatus;
use error::{ProcError, ProcFile, ProcOper};
use TaskId;

/// A struct containing information about a process.
///
/// This struct contains information from various files inside the
/// /proc/[pid] directory (for the respective pid).
#[derive(Debug)]
pub struct Pid {
    /// The tid of this process
    pub pid: TaskId,
    /// The /proc/[pid]/stat file
    pub stat: Box<PidStat>,
    /// The /proc/[pid]/status file
    pub status: Box<PidStatus>,
    /// The /proc/[pid]/cmdline file
    pub cmdline: Vec<String>,
    /// If this is a thread, this is set to true.
    /// Threads will never have tasks attached.
    is_thread: bool,
    /// Vec of threads under /proc/[pid]/tasks/[tid]
    threads: Option<Vec<Pid>>,
}

impl Pid {
    /// Create a new Pid struct for a process, given a pid.
    pub fn new(pid: TaskId) -> Result<Self, ProcError> {
        let pid_dir = Path::new("/proc");
        Self::new_dir(pid_dir, pid)
    }

    fn new_dir(proc_dir: &Path, pid: TaskId) -> Result<Self, ProcError> {
        let proc_dir = proc_dir.join(pid.to_string());
        let pid_stat = try!(PidStat::new(&proc_dir));
        let pid_status = try!(PidStatus::new(&proc_dir));
        let cmdline = try!(Self::read_cmdline(&proc_dir));

        Ok(Pid {
            pid: pid,
            stat: Box::new(pid_stat),
            status: Box::new(pid_status),
            cmdline: cmdline,
            is_thread: false,
            threads: None,
        })
    }

    /// Given a /proc/[pid] directory, read the respective /proc/[pid]/cmdline
    /// file and return them in a Vec.
    fn read_cmdline(proc_dir: &Path) -> Result<Vec<String>, ProcError> {
        File::open(proc_dir.join("cmdline"))
            .map_err(|e| ProcError::new_err(ProcOper::Opening, ProcFile::PidCmdline, e))
            .and_then(|file| {
                let mut contents = Vec::new();
                try!(
                    BufReader::with_capacity(4096, file)
                        .read_to_end(&mut contents)
                        .map_err(|e| ProcError::new_err(ProcOper::Reading, ProcFile::PidCmdline, e))
                );
                if contents.ends_with(&['\0' as u8]) {
                    let _ = contents.pop();
                }
                Ok(contents)
            }).and_then(|contents| {
                String::from_utf8(contents)
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::PidCmdline,
                                    Some("parsing utf8"))))
            }).map(|contents|
                contents
                    .split('\0')
                    .map(|a| a.to_string())
                    .collect()
            )
    }

    /// Determine whether this process matches this query
    fn query(&self, query: &PidQuery) -> bool {
        match *query {
            PidQuery::PidQuery(q) => PidQuery::taskid_query(self.stat.pid, q),
            PidQuery::PpidQuery(q) => PidQuery::taskid_query(self.stat.ppid, q),
            PidQuery::NameQuery(ref q) => PidQuery::string_query(&self.stat.comm, &q),
            PidQuery::CmdlineQuery(ref q) => PidQuery::string_query(&self.cmdline.join(" "), &q),
            PidQuery::NoneQuery => true
        }
    }

    pub fn tasks(&mut self) -> Option<Vec<Pid>> {
        self.tasks_query(PidQuery::NoneQuery)
    }

    // TODO: Work out if this really should return Option<_>
    // or Option<Result<Vec<Pid>>>. Otherwise the error is uncaught.
    pub fn tasks_query(&self, query: PidQuery) -> Option<Vec<Pid>> {
        if self.is_thread {
            return None;
        }

        PidIter::new_tid_query(self.pid, query.clone()).unwrap()
            .filter(|p| {
                let query = query.clone();
                match *p {
                    Ok(ref pid) => pid.query(&query),
                    Err(_) => true
                }
            }).collect::<Result<Vec<_>, _>>().ok()
    }
}

impl PartialEq for Pid {
    fn eq(&self, other: &Self) -> bool {
        self.stat.pid.eq(&other.stat.pid)
    }
}

impl Eq for Pid {}
impl PartialOrd for Pid {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for Pid {
    fn cmp(&self, other: &Self) -> Ordering {
        self.stat.pid.cmp(&other.stat.pid)
    }
}

/// An Iterator over processes in the system.
///
/// If a process disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct PidIter {
    dir: String,
    dir_iter: ReadDir,
    query: PidQuery,
}

impl PidIter {
    /// Create a new iterator over all processes in /proc.
    pub fn new() -> Result<Self, ProcError> {
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all processes in /proc, but only yield
    /// processes that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = "/proc".to_owned();
        let proc_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(proc_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::ProcDir, Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query,
        })
    }

    fn new_tid_query(pid: TaskId, query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = format!("/proc/{}/task", pid);
        let task_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(task_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::PidTaskDir,
                        Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query
        })
    }

    /// Given a DirEntry, try to create a Pid struct, and only return if
    /// it matches the query, and is complete.
    fn proc_dir_filter(entry_opt: Result<DirEntry, io::Error>, query: &PidQuery, dir_name: &str)
        -> Option<Result<Pid, ProcError>> {
        let file = entry_opt
            .map_err(|e|
                ProcError::new(ProcOper::Reading, ProcFile::ProcDir, Some(e), Some("PidIter"))
            )
            .and_then(|entry|
                entry.file_name().into_string()
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::ProcDir, Some("PidIter"))))
            );

        if let Err(e) = file{
            return Some(Err(e));
        }

        // Ensure filename is an integer (skip if not)
        match file.unwrap().parse() {
            Ok(pid) => {
                // If an error is not hard (error opening or reading file),
                // do not error as it may be a now-dead process.
                // If a parsing error occurs, then do return an error.
                let prc = match Pid::new_dir(Path::new(&dir_name), pid) {
                    Ok(prc) => prc,
                    Err(e) => {
                        if e.is_hard() {
                            return Some(Err(e));
                        } else {
                            return None;
                        }
                    }
                };
                match prc.query(&query) {
                    true => Some(Ok(prc)),
                    false => None
                }
            },
            Err(_) => None
        }
    }
}

impl Iterator for PidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        for entry in self.dir_iter.by_ref() {
            match Self::proc_dir_filter(entry, &self.query, &self.dir) {
                some @ Some(_) => return some,
                None => continue
            }
        }
        None
    }

    /// Size may be anywhere from 0 to number of dirs.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, self.dir_iter.size_hint().1)
    }
}

/// An Iterator over threads of processes in the system.
///
/// If a task disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct TidIter {
    pid_iter: PidIter,
    task_iter: Option<vec::IntoIter<Pid>>,
    query: PidQuery,
}

impl TidIter {
    /// Create a new iterator over all tasks in /proc.
    pub fn new() -> Result<Self, ProcError> {
            println!("{:?}", 3);
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all tasks in /proc, but only yield
    /// those that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        Ok(TidIter{
            pid_iter: try!(PidIter::new_query(query.clone())),
            task_iter: None,
            query: query,
        })
    }
}

impl Iterator for TidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.task_iter.is_none() {
                let pid = match self.pid_iter.next() {
                    Some(Ok(pid)) => pid,
                    Some(Err(e)) => { return Some(Err(e)) },
                    None => { return None; }
                };
                let tasks_vec = pid.tasks_query(self.query.clone());
                if let Some(vec) = tasks_vec {
                    self.task_iter = Some(vec.into_iter());
                }
                continue;
            } else {
                let next = self.task_iter.as_mut().unwrap().next();
                match next {
                    Some(pid) => { return Some(Ok(pid)); },
                    None => { self.task_iter = None; },
                };
            }
        }
    }
}

#[derive(Clone, Debug)]
/// A list of query types for process querying.
pub enum PidQuery {
    /// Query by pid
    PidQuery(TaskId),
    /// Query by ppid
    PpidQuery(TaskId),
    /// Query by program name
    NameQuery(String),
    /// Query by cmdline contents (joined with space)
    CmdlineQuery(String),
    /// An empty query that always matches
    NoneQuery
}

impl PidQuery {
    /// Given a user-specified query string, decode it into
    /// an appropriate query.
    ///
    /// Bare number -> PidQuery
    /// Bare string -> NameQuery
    ///
    /// type=query is supported for the following types;
    /// pid -> PidQuery
    /// ppid -> PpidQuery
    /// name -> NameQuery
    /// cmdline -> CmdlineQuery
    fn create_query(query: &str) -> Result<PidQuery, String> {
        let splits: Vec<_> = query.splitn(2, '=').collect();

        match splits.len() {
            0 => Ok(PidQuery::NoneQuery),
            1 => Ok(match query.parse().ok() {
                Some(tid) => PidQuery::PidQuery(tid),
                None => PidQuery::NameQuery(query.to_owned())
            }),
            _ => {
                let q_text = splits[1].to_owned();
                let q_tid = q_text.parse();
                match &*splits[0].to_lowercase() {
                    "pid" => q_tid.map(|q| PidQuery::PidQuery(q))
                        .or(Err("Query value for type 'pid' not valid".to_owned())),
                    "ppid" => q_tid.map(|q| PidQuery::PpidQuery(q))
                        .or(Err("Query value for type 'ppid' not valid".to_owned())),
                    "name" => Ok(PidQuery::NameQuery(q_text)),
                    "cmdline" => Ok(PidQuery::CmdlineQuery(q_text)),
                    _ => Err("Invalid query type".to_owned())
                }
            }
        }
    }

    /// Match a pid by simple equality.
    pub fn taskid_query(tid: TaskId, query: TaskId) -> bool {
        tid == query
    }

    /// For strings, use a substring search.
    pub fn string_query(text: &str, query: &str) -> bool {
        text.contains(query)
    }
}

impl FromStr for PidQuery {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::create_query(s)
    }
}
<commit_msg>Change procps/pid/(stat|status).pm modules to be pub<commit_after>use std::io;
use std::io::prelude::*;
use std::fs::{self, File, ReadDir, DirEntry};
use std::path::Path;
use std::vec;
use std::io::BufReader;
use std::cmp::Ordering;
use std::str::FromStr;

/// Get process stats (/proc/[pid]/stat)
pub mod stat;
/// Get process status (/proc/[pid]/status)
pub mod status;

use self::stat::PidStat;
use self::status::PidStatus;
use error::{ProcError, ProcFile, ProcOper};
use TaskId;

/// A struct containing information about a process.
///
/// This struct contains information from various files inside the
/// /proc/[pid] directory (for the respective pid).
#[derive(Debug)]
pub struct Pid {
    /// The tid of this process
    pub pid: TaskId,
    /// The /proc/[pid]/stat file
    pub stat: Box<PidStat>,
    /// The /proc/[pid]/status file
    pub status: Box<PidStatus>,
    /// The /proc/[pid]/cmdline file
    pub cmdline: Vec<String>,
    /// If this is a thread, this is set to true.
    /// Threads will never have tasks attached.
    is_thread: bool,
    /// Vec of threads under /proc/[pid]/tasks/[tid]
    threads: Option<Vec<Pid>>,
}

impl Pid {
    /// Create a new Pid struct for a process, given a pid.
    pub fn new(pid: TaskId) -> Result<Self, ProcError> {
        let pid_dir = Path::new("/proc");
        Self::new_dir(pid_dir, pid)
    }

    fn new_dir(proc_dir: &Path, pid: TaskId) -> Result<Self, ProcError> {
        let proc_dir = proc_dir.join(pid.to_string());
        let pid_stat = try!(PidStat::new(&proc_dir));
        let pid_status = try!(PidStatus::new(&proc_dir));
        let cmdline = try!(Self::read_cmdline(&proc_dir));

        Ok(Pid {
            pid: pid,
            stat: Box::new(pid_stat),
            status: Box::new(pid_status),
            cmdline: cmdline,
            is_thread: false,
            threads: None,
        })
    }

    /// Given a /proc/[pid] directory, read the respective /proc/[pid]/cmdline
    /// file and return them in a Vec.
    fn read_cmdline(proc_dir: &Path) -> Result<Vec<String>, ProcError> {
        File::open(proc_dir.join("cmdline"))
            .map_err(|e| ProcError::new_err(ProcOper::Opening, ProcFile::PidCmdline, e))
            .and_then(|file| {
                let mut contents = Vec::new();
                try!(
                    BufReader::with_capacity(4096, file)
                        .read_to_end(&mut contents)
                        .map_err(|e| ProcError::new_err(ProcOper::Reading, ProcFile::PidCmdline, e))
                );
                if contents.ends_with(&['\0' as u8]) {
                    let _ = contents.pop();
                }
                Ok(contents)
            }).and_then(|contents| {
                String::from_utf8(contents)
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::PidCmdline,
                                    Some("parsing utf8"))))
            }).map(|contents|
                contents
                    .split('\0')
                    .map(|a| a.to_string())
                    .collect()
            )
    }

    /// Determine whether this process matches this query
    fn query(&self, query: &PidQuery) -> bool {
        match *query {
            PidQuery::PidQuery(q) => PidQuery::taskid_query(self.stat.pid, q),
            PidQuery::PpidQuery(q) => PidQuery::taskid_query(self.stat.ppid, q),
            PidQuery::NameQuery(ref q) => PidQuery::string_query(&self.stat.comm, &q),
            PidQuery::CmdlineQuery(ref q) => PidQuery::string_query(&self.cmdline.join(" "), &q),
            PidQuery::NoneQuery => true
        }
    }

    pub fn tasks(&mut self) -> Option<Vec<Pid>> {
        self.tasks_query(PidQuery::NoneQuery)
    }

    // TODO: Work out if this really should return Option<_>
    // or Option<Result<Vec<Pid>>>. Otherwise the error is uncaught.
    pub fn tasks_query(&self, query: PidQuery) -> Option<Vec<Pid>> {
        if self.is_thread {
            return None;
        }

        PidIter::new_tid_query(self.pid, query.clone()).unwrap()
            .filter(|p| {
                let query = query.clone();
                match *p {
                    Ok(ref pid) => pid.query(&query),
                    Err(_) => true
                }
            }).collect::<Result<Vec<_>, _>>().ok()
    }
}

impl PartialEq for Pid {
    fn eq(&self, other: &Self) -> bool {
        self.stat.pid.eq(&other.stat.pid)
    }
}

impl Eq for Pid {}
impl PartialOrd for Pid {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for Pid {
    fn cmp(&self, other: &Self) -> Ordering {
        self.stat.pid.cmp(&other.stat.pid)
    }
}

/// An Iterator over processes in the system.
///
/// If a process disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct PidIter {
    dir: String,
    dir_iter: ReadDir,
    query: PidQuery,
}

impl PidIter {
    /// Create a new iterator over all processes in /proc.
    pub fn new() -> Result<Self, ProcError> {
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all processes in /proc, but only yield
    /// processes that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = "/proc".to_owned();
        let proc_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(proc_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::ProcDir, Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query,
        })
    }

    fn new_tid_query(pid: TaskId, query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = format!("/proc/{}/task", pid);
        let task_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(task_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::PidTaskDir,
                        Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query
        })
    }

    /// Given a DirEntry, try to create a Pid struct, and only return if
    /// it matches the query, and is complete.
    fn proc_dir_filter(entry_opt: Result<DirEntry, io::Error>, query: &PidQuery, dir_name: &str)
        -> Option<Result<Pid, ProcError>> {
        let file = entry_opt
            .map_err(|e|
                ProcError::new(ProcOper::Reading, ProcFile::ProcDir, Some(e), Some("PidIter"))
            )
            .and_then(|entry|
                entry.file_name().into_string()
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::ProcDir, Some("PidIter"))))
            );

        if let Err(e) = file{
            return Some(Err(e));
        }

        // Ensure filename is an integer (skip if not)
        match file.unwrap().parse() {
            Ok(pid) => {
                // If an error is not hard (error opening or reading file),
                // do not error as it may be a now-dead process.
                // If a parsing error occurs, then do return an error.
                let prc = match Pid::new_dir(Path::new(&dir_name), pid) {
                    Ok(prc) => prc,
                    Err(e) => {
                        if e.is_hard() {
                            return Some(Err(e));
                        } else {
                            return None;
                        }
                    }
                };
                match prc.query(&query) {
                    true => Some(Ok(prc)),
                    false => None
                }
            },
            Err(_) => None
        }
    }
}

impl Iterator for PidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        for entry in self.dir_iter.by_ref() {
            match Self::proc_dir_filter(entry, &self.query, &self.dir) {
                some @ Some(_) => return some,
                None => continue
            }
        }
        None
    }

    /// Size may be anywhere from 0 to number of dirs.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, self.dir_iter.size_hint().1)
    }
}

/// An Iterator over threads of processes in the system.
///
/// If a task disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct TidIter {
    pid_iter: PidIter,
    task_iter: Option<vec::IntoIter<Pid>>,
    query: PidQuery,
}

impl TidIter {
    /// Create a new iterator over all tasks in /proc.
    pub fn new() -> Result<Self, ProcError> {
            println!("{:?}", 3);
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all tasks in /proc, but only yield
    /// those that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        Ok(TidIter{
            pid_iter: try!(PidIter::new_query(query.clone())),
            task_iter: None,
            query: query,
        })
    }
}

impl Iterator for TidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.task_iter.is_none() {
                let pid = match self.pid_iter.next() {
                    Some(Ok(pid)) => pid,
                    Some(Err(e)) => { return Some(Err(e)) },
                    None => { return None; }
                };
                let tasks_vec = pid.tasks_query(self.query.clone());
                if let Some(vec) = tasks_vec {
                    self.task_iter = Some(vec.into_iter());
                }
                continue;
            } else {
                let next = self.task_iter.as_mut().unwrap().next();
                match next {
                    Some(pid) => { return Some(Ok(pid)); },
                    None => { self.task_iter = None; },
                };
            }
        }
    }
}

#[derive(Clone, Debug)]
/// A list of query types for process querying.
pub enum PidQuery {
    /// Query by pid
    PidQuery(TaskId),
    /// Query by ppid
    PpidQuery(TaskId),
    /// Query by program name
    NameQuery(String),
    /// Query by cmdline contents (joined with space)
    CmdlineQuery(String),
    /// An empty query that always matches
    NoneQuery
}

impl PidQuery {
    /// Given a user-specified query string, decode it into
    /// an appropriate query.
    ///
    /// Bare number -> PidQuery
    /// Bare string -> NameQuery
    ///
    /// type=query is supported for the following types;
    /// pid -> PidQuery
    /// ppid -> PpidQuery
    /// name -> NameQuery
    /// cmdline -> CmdlineQuery
    fn create_query(query: &str) -> Result<PidQuery, String> {
        let splits: Vec<_> = query.splitn(2, '=').collect();

        match splits.len() {
            0 => Ok(PidQuery::NoneQuery),
            1 => Ok(match query.parse().ok() {
                Some(tid) => PidQuery::PidQuery(tid),
                None => PidQuery::NameQuery(query.to_owned())
            }),
            _ => {
                let q_text = splits[1].to_owned();
                let q_tid = q_text.parse();
                match &*splits[0].to_lowercase() {
                    "pid" => q_tid.map(|q| PidQuery::PidQuery(q))
                        .or(Err("Query value for type 'pid' not valid".to_owned())),
                    "ppid" => q_tid.map(|q| PidQuery::PpidQuery(q))
                        .or(Err("Query value for type 'ppid' not valid".to_owned())),
                    "name" => Ok(PidQuery::NameQuery(q_text)),
                    "cmdline" => Ok(PidQuery::CmdlineQuery(q_text)),
                    _ => Err("Invalid query type".to_owned())
                }
            }
        }
    }

    /// Match a pid by simple equality.
    pub fn taskid_query(tid: TaskId, query: TaskId) -> bool {
        tid == query
    }

    /// For strings, use a substring search.
    pub fn string_query(text: &str, query: &str) -> bool {
        text.contains(query)
    }
}

impl FromStr for PidQuery {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::create_query(s)
    }
}
<|endoftext|>


<commit_before>use std::string;
use std::{char, f64, fmt, io, num, str, mem};
use std::ffi::CString;
use rustc_serialize as serialize;
use std::marker::PhantomData;
use proton_sys;

/*
Marshal encodes a Rust value as AMQP data in buffer based on its type.
If buffer is nil, or is not large enough, a new buffer  is created.

Returns the buffer used for encoding with len() adjusted to the actual size of data.

Rust types are encoded as follows

 +-------------------------------------+--------------------------------------------+
 |Rust type                            |AMQP type                                   |
 +-------------------------------------+--------------------------------------------+
 |bool                                 |bool                                        |
 +-------------------------------------+--------------------------------------------+
 |int8, int16, int32, int64 (int)      |byte, short, int, long (int or long)        |
 +-------------------------------------+--------------------------------------------+
 |uint8, uint16, uint32, uint64 (uint) |ubyte, ushort, uint, ulong (uint or ulong)  |
 +-------------------------------------+--------------------------------------------+
 |float32, float64                     |float, double.                              |
 +-------------------------------------+--------------------------------------------+
 |string                               |string                                      |
 +-------------------------------------+--------------------------------------------+
 |[]byte, Binary                       |binary                                      |
 +-------------------------------------+--------------------------------------------+
 |Symbol                               |symbol                                      |
 +-------------------------------------+--------------------------------------------+
 |interface{}                          |the contained type                          |
 +-------------------------------------+--------------------------------------------+
 |nil                                  |null                                        |
 +-------------------------------------+--------------------------------------------+
 |map[K]T                              |map with K and T converted as above         |
 +-------------------------------------+--------------------------------------------+
 |Map                                  |map, may have mixed types for keys, values  |
 +-------------------------------------+--------------------------------------------+
 |[]T                                  |list with T converted as above              |
 +-------------------------------------+--------------------------------------------+
 |List                                 |list, may have mixed types  values          |
 +-------------------------------------+--------------------------------------------+

TODO: Update the table to match rust types
TODO Rust types: array, slice, struct

Rust types that cannot be marshaled: complex64/128, uintptr, function, interface, channel
*/

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ErrorCode {
// ADD SOMETHING HERE
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ParserError {
    /// msg, line, col
    SyntaxError(ErrorCode, usize, usize),
    IoError(io::ErrorKind, &'static str),
}

// Builder and Parser have the same errors.
pub type BuilderError = ParserError;

#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParseError(ParserError),
    ExpectedError(string::String, string::String),
    MissingFieldError(string::String),
    UnknownVariantError(string::String),
    ApplicationError(string::String)
}

#[derive(Clone, Copy, Debug)]
pub enum EncoderError {
    FmtError(fmt::Error),
    BadHashmapKey,
}

pub type EncodeResult = Result<(), EncoderError>;
pub type DecodeResult<T> = Result<T, DecoderError>;

pub struct Encoder<'e> {
    data: *mut proton_sys::pn_data_t,
    __phantom: PhantomData<&'e ()>
}

impl<'e> Encoder<'e> {
    fn new() -> Encoder<'e> {
        Encoder::with_capacity(16)
    }

    fn with_capacity(capacity: ::libc::size_t) -> Encoder<'e> {
        let data = unsafe{proton_sys::pn_data(capacity)};
        Encoder {data: data, __phantom: PhantomData}
    }
}

impl<'a> serialize::Encoder for Encoder<'a> {
    type Error = EncoderError;

    fn emit_nil(&mut self) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_null(&mut *self.data);})
    }

    fn emit_usize(&mut self, v: usize) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_uint(&mut *self.data, v as u32);})
    }
    fn emit_u64(&mut self, v: u64) -> EncodeResult {
        // NOTE(flaper87): check word size
        Ok(unsafe{proton_sys::pn_data_put_ulong(&mut *self.data, v);})
    }
    fn emit_u32(&mut self, v: u32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_uint(&mut *self.data, v);})
    }
    fn emit_u16(&mut self, v: u16) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_ushort(&mut *self.data, v);})
    }
    fn emit_u8(&mut self, v: u8) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_ubyte(&mut *self.data, v);})
    }

    fn emit_isize(&mut self, v: isize) -> EncodeResult {
        // NOTE(flaper87): check word size
        Ok(unsafe{proton_sys::pn_data_put_int(&mut *self.data, v as i32);})
    }
    fn emit_i64(&mut self, v: i64) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_long(&mut *self.data, v);})
    }
    fn emit_i32(&mut self, v: i32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_int(&mut *self.data, v);})
    }
    fn emit_i16(&mut self, v: i16) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_short(&mut *self.data, v);})
    }
    fn emit_i8(&mut self, v: i8) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_byte(&mut *self.data, v);})
    }

    fn emit_bool(&mut self, v: bool) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_bool(&mut *self.data, v as u8);})
    }

    fn emit_f64(&mut self, v: f64) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_float(&mut *self.data, v as f32);})
    }
    fn emit_f32(&mut self, v: f32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_float(&mut *self.data, v);})
    }

    fn emit_char(&mut self, v: char) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_char(&mut *self.data, v as u32);})
    }

    fn emit_str(&mut self, slice: &str) -> EncodeResult {
        Ok(unsafe{
            let s = CString::new(slice).unwrap();
            let bytes = proton_sys::pn_bytes(slice.len() as proton_sys::size_t, s.as_ptr());
            proton_sys::pn_data_put_string(&mut *self.data, bytes);})
    }

    fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_enum_variant<F>(&mut self,
                            name: &str,
                            _id: usize,
                            cnt: usize,
                            f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_enum_struct_variant<F>(&mut self,
                                   name: &str,
                                   id: usize,
                                   cnt: usize,
                                   f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum_variant(name, id, cnt, f)
    }

    fn emit_enum_struct_variant_field<F>(&mut self,
                                         _: &str,
                                         idx: usize,
                                         f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum_variant_arg(idx, f)
    }

    fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq_elt(idx, f)
    }

    fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq_elt(idx, f)
    }

    fn emit_option<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }
    fn emit_option_none(&mut self) -> EncodeResult {
        self.emit_nil()
    }
    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_seq<F>(&mut self, _len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_map<F>(&mut self, _len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }
}

/// Shortcut function to encode a `T` into a JSON `String`
pub fn encode<T: serialize::Encodable>(object: &T) -> Result<Vec<i8>, EncoderError> {
    let mut encoder = Encoder::new();
    try!(object.encode(&mut encoder));
    let mut size = 1024;
    let mut bytes = Vec::with_capacity(size);
    let mut result = proton_sys::PN_OVERFLOW;

    while result == proton_sys::PN_OVERFLOW {
        result = unsafe{proton_sys::pn_data_encode(encoder.data,
                                                   bytes.as_mut_ptr(),
                                                   size as u64) as i8};

        if result > 0 {
            unsafe {bytes.set_len(result as usize);}
            break;
        } else if result <= 0 {
            // not ok
            println!("ERROR");
            break;
        }

        size *= 2;
        bytes = Vec::with_capacity(size);
    }

    bytes.shrink_to_fit();
    Ok(bytes)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ffi::CStr;
    use std::slice;
    use std::str;
    use proton_sys;

    fn get_type_name<'a>(data: *mut proton_sys::pn_data_t) -> &'a str {
        unsafe{
            let t = proton_sys::pn_data_type(data);
            let name = proton_sys::pn_type_name(t);
            CStr::from_ptr(name).to_str().unwrap()
        }
    }

    #[test]
    fn test_string_encoding() {
        let value = "testing";
        let encoded = encode(&value).unwrap();
        let data;
        unsafe {
            data = proton_sys::pn_data(1024);
            let err = proton_sys::pn_data_decode(data,
                                                 encoded.as_ptr(),
                                                 encoded.len() as u64);
        }

        assert_eq!(1, unsafe{proton_sys::pn_data_size(data)});
        assert_eq!("PN_STRING", get_type_name(data));

        let data_content = unsafe {
            let pn_bytes = proton_sys::pn_data_get_string(data);
            let data: &[u8] = slice::from_raw_parts(pn_bytes.start as *const u8,
                                                    pn_bytes.size as usize);
            str::from_utf8(data).unwrap()
        };
        assert_eq!(value, data_content);

    }

    #[test]
    fn test_u8_encoding() {
        let value = 1u8;
        let encoded = encode(&value).unwrap();
        let data;
        unsafe {
            data = proton_sys::pn_data(1024);
            let err = proton_sys::pn_data_decode(data,
                                                 encoded.as_ptr(),
                                                 encoded.len() as u64);
        }

        assert_eq!(1, unsafe{proton_sys::pn_data_size(data)});
        assert_eq!("PN_UBYTE", get_type_name(data));

        let data_content = unsafe {
            proton_sys::pn_data_get_ubyte(data)
        };
        assert_eq!(value, data_content);

    }
}
<commit_msg>use macros for tests<commit_after>use std::string;
use std::{char, f64, fmt, io, num, str, mem};
use std::ffi::CString;
use rustc_serialize as serialize;
use std::marker::PhantomData;
use proton_sys;

/*
Marshal encodes a Rust value as AMQP data in buffer based on its type.
If buffer is nil, or is not large enough, a new buffer  is created.

Returns the buffer used for encoding with len() adjusted to the actual size of data.

Rust types are encoded as follows

 +-------------------------------------+--------------------------------------------+
 |Rust type                            |AMQP type                                   |
 +-------------------------------------+--------------------------------------------+
 |bool                                 |bool                                        |
 +-------------------------------------+--------------------------------------------+
 |int8, int16, int32, int64 (int)      |byte, short, int, long (int or long)        |
 +-------------------------------------+--------------------------------------------+
 |uint8, uint16, uint32, uint64 (uint) |ubyte, ushort, uint, ulong (uint or ulong)  |
 +-------------------------------------+--------------------------------------------+
 |float32, float64                     |float, double.                              |
 +-------------------------------------+--------------------------------------------+
 |string                               |string                                      |
 +-------------------------------------+--------------------------------------------+
 |[]byte, Binary                       |binary                                      |
 +-------------------------------------+--------------------------------------------+
 |Symbol                               |symbol                                      |
 +-------------------------------------+--------------------------------------------+
 |interface{}                          |the contained type                          |
 +-------------------------------------+--------------------------------------------+
 |nil                                  |null                                        |
 +-------------------------------------+--------------------------------------------+
 |map[K]T                              |map with K and T converted as above         |
 +-------------------------------------+--------------------------------------------+
 |Map                                  |map, may have mixed types for keys, values  |
 +-------------------------------------+--------------------------------------------+
 |[]T                                  |list with T converted as above              |
 +-------------------------------------+--------------------------------------------+
 |List                                 |list, may have mixed types  values          |
 +-------------------------------------+--------------------------------------------+

TODO: Update the table to match rust types
TODO Rust types: array, slice, struct

Rust types that cannot be marshaled: complex64/128, uintptr, function, interface, channel
*/

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ErrorCode {
// ADD SOMETHING HERE
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ParserError {
    /// msg, line, col
    SyntaxError(ErrorCode, usize, usize),
    IoError(io::ErrorKind, &'static str),
}

// Builder and Parser have the same errors.
pub type BuilderError = ParserError;

#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParseError(ParserError),
    ExpectedError(string::String, string::String),
    MissingFieldError(string::String),
    UnknownVariantError(string::String),
    ApplicationError(string::String)
}

#[derive(Clone, Copy, Debug)]
pub enum EncoderError {
    FmtError(fmt::Error),
    BadHashmapKey,
}

pub type EncodeResult = Result<(), EncoderError>;
pub type DecodeResult<T> = Result<T, DecoderError>;

pub struct Encoder<'e> {
    data: *mut proton_sys::pn_data_t,
    __phantom: PhantomData<&'e ()>
}

impl<'e> Encoder<'e> {
    fn new() -> Encoder<'e> {
        Encoder::with_capacity(16)
    }

    fn with_capacity(capacity: ::libc::size_t) -> Encoder<'e> {
        let data = unsafe{proton_sys::pn_data(capacity)};
        Encoder {data: data, __phantom: PhantomData}
    }
}

impl<'a> serialize::Encoder for Encoder<'a> {
    type Error = EncoderError;

    fn emit_nil(&mut self) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_null(&mut *self.data);})
    }

    fn emit_usize(&mut self, v: usize) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_uint(&mut *self.data, v as u32);})
    }
    fn emit_u64(&mut self, v: u64) -> EncodeResult {
        // NOTE(flaper87): check word size
        Ok(unsafe{proton_sys::pn_data_put_ulong(&mut *self.data, v);})
    }
    fn emit_u32(&mut self, v: u32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_uint(&mut *self.data, v);})
    }
    fn emit_u16(&mut self, v: u16) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_ushort(&mut *self.data, v);})
    }
    fn emit_u8(&mut self, v: u8) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_ubyte(&mut *self.data, v);})
    }

    fn emit_isize(&mut self, v: isize) -> EncodeResult {
        // NOTE(flaper87): check word size
        Ok(unsafe{proton_sys::pn_data_put_int(&mut *self.data, v as i32);})
    }
    fn emit_i64(&mut self, v: i64) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_long(&mut *self.data, v);})
    }
    fn emit_i32(&mut self, v: i32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_int(&mut *self.data, v);})
    }
    fn emit_i16(&mut self, v: i16) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_short(&mut *self.data, v);})
    }
    fn emit_i8(&mut self, v: i8) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_byte(&mut *self.data, v);})
    }

    fn emit_bool(&mut self, v: bool) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_bool(&mut *self.data, v as u8);})
    }

    fn emit_f64(&mut self, v: f64) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_float(&mut *self.data, v as f32);})
    }
    fn emit_f32(&mut self, v: f32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_float(&mut *self.data, v);})
    }

    fn emit_char(&mut self, v: char) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_char(&mut *self.data, v as u32);})
    }

    fn emit_str(&mut self, slice: &str) -> EncodeResult {
        Ok(unsafe{
            let s = CString::new(slice).unwrap();
            let bytes = proton_sys::pn_bytes(slice.len() as proton_sys::size_t, s.as_ptr());
            proton_sys::pn_data_put_string(&mut *self.data, bytes);})
    }

    fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_enum_variant<F>(&mut self,
                            name: &str,
                            _id: usize,
                            cnt: usize,
                            f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_enum_struct_variant<F>(&mut self,
                                   name: &str,
                                   id: usize,
                                   cnt: usize,
                                   f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum_variant(name, id, cnt, f)
    }

    fn emit_enum_struct_variant_field<F>(&mut self,
                                         _: &str,
                                         idx: usize,
                                         f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum_variant_arg(idx, f)
    }

    fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq_elt(idx, f)
    }

    fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq_elt(idx, f)
    }

    fn emit_option<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }
    fn emit_option_none(&mut self) -> EncodeResult {
        self.emit_nil()
    }
    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_seq<F>(&mut self, _len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_map<F>(&mut self, _len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }
}

/// Shortcut function to encode a `T` into a JSON `String`
pub fn encode<T: serialize::Encodable>(object: &T) -> Result<Vec<i8>, EncoderError> {
    let mut encoder = Encoder::new();
    try!(object.encode(&mut encoder));
    let mut size = 1024;
    let mut bytes = Vec::with_capacity(size);
    let mut result = proton_sys::PN_OVERFLOW;

    while result == proton_sys::PN_OVERFLOW {
        result = unsafe{proton_sys::pn_data_encode(encoder.data,
                                                   bytes.as_mut_ptr(),
                                                   size as u64) as i8};

        if result > 0 {
            unsafe {bytes.set_len(result as usize);}
            break;
        } else if result <= 0 {
            // not ok
            println!("ERROR");
            break;
        }

        size *= 2;
        bytes = Vec::with_capacity(size);
    }

    bytes.shrink_to_fit();
    Ok(bytes)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ffi::CStr;
    use std::slice;
    use std::str;
    use proton_sys;

    macro_rules! create_test {
        ($func:ident, $get_data:ident, $value:expr) => (
            #[test]
            fn $func() {
                let value = $value;
                let encoded = encode(&value).unwrap();
                let data;
                unsafe {
                    data = proton_sys::pn_data(1024);
                    let err = proton_sys::pn_data_decode(data,
                                                         encoded.as_ptr(),
                                                         encoded.len() as u64);
                }

                assert_eq!(1, unsafe{proton_sys::pn_data_size(data)});
                assert_eq!(format!("pn_{:}", stringify!($func)),
                           get_type_name(data).to_lowercase());

                let data_content = unsafe {
                    //concat_idents!(proton_sys::pn_data_get_, $func)(data)
                    proton_sys::$get_data(data)
                };
                assert_eq!(value, data_content);
            }
        )
    }

    fn get_type_name<'a>(data: *mut proton_sys::pn_data_t) -> &'a str {
        unsafe{
            let t = proton_sys::pn_data_type(data);
            let name = proton_sys::pn_type_name(t);
            CStr::from_ptr(name).to_str().unwrap()
        }
    }

    #[test]
    fn test_string_encoding() {
        let value = "testing";
        let encoded = encode(&value).unwrap();
        let data;
        unsafe {
            data = proton_sys::pn_data(1024);
            let err = proton_sys::pn_data_decode(data,
                                                 encoded.as_ptr(),
                                                 encoded.len() as u64);
        }

        assert_eq!(1, unsafe{proton_sys::pn_data_size(data)});
        assert_eq!("PN_STRING", get_type_name(data));

        let data_content = unsafe {
            let pn_bytes = proton_sys::pn_data_get_string(data);
            let data: &[u8] = slice::from_raw_parts(pn_bytes.start as *const u8,
                                                    pn_bytes.size as usize);
            str::from_utf8(data).unwrap()
        };
        assert_eq!(value, data_content);

    }

    create_test!(ubyte, pn_data_get_ubyte, 1u8);
    create_test!(ushort, pn_data_get_ushort, 1u16);
    create_test!(uint, pn_data_get_uint, 1u32);
    create_test!(ulong, pn_data_get_ulong, 1u64);

    create_test!(byte, pn_data_get_byte, 1i8);
    create_test!(short, pn_data_get_short, 1i16);
    create_test!(int, pn_data_get_int, 1i32);
    create_test!(long, pn_data_get_long, 1i64);
}
<|endoftext|>


<commit_before>use crate::ram::cell::*;
use crate::ram::chunk::Chunks;
use crate::ram::schema::*;
use crate::ram::types;
use crate::ram::types::*;

use super::*;

pub const CHUNK_SIZE: usize = 8 * 1024 * 1024;

#[cfg(feature = "fast_map")]
#[test]
pub fn cell_rw() {
    let fields = default_fields();
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let schema = Schema {
        id: 1,
        name: String::from("dummy"),
        key_field: None,
        str_key_field: None,
        fields,
        is_dynamic: false,
    };
    let mut data = data_map_value! {
        id: 100 as i64,
        score: 70 as u64,
        name: String::from("Jack")
    };
    let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
    chunk.meta.schemas.new_schema(schema.clone());
    let mut cell = OwnedCell {
        header: CellHeader::new(0, schema.id, &id1),
        data,
    };
    let mut loc = chunk.write_cell_to_chunk(&mut cell);
    let cell_1_ptr = loc.unwrap().0;
    {
        let (stored_cell, _) = SharedCellData::from_chunk_raw(cell_1_ptr, &chunk).unwrap();
        assert_eq!(stored_cell.header.size, 24);
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
    data = data_map_value! {
        id: 2 as i64,
        score: 80 as u64,
        name: "John"
    };
    cell = OwnedCell {
        header: CellHeader::new(0, schema.id, &id2),
        data,
    };
    loc = chunk.write_cell_to_chunk(&mut cell);
    let cell_2_ptr = loc.unwrap().0;

    assert_eq!(cell_2_ptr, cell_1_ptr + cell.header.size as usize);
    {
        let stored_cell = SharedCellData::from_chunk_raw(cell_2_ptr, &chunk)
            .unwrap()
            .0;
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &80);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
    }
    {
        let stored_cell = SharedCellData::from_chunk_raw(cell_1_ptr, &chunk)
            .unwrap()
            .0;
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
}

#[cfg(feature = "fast_map")]
#[test]
pub fn dynamic() {
    let fields = default_fields();
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let schema = Schema {
        id: 1,
        name: String::from("dummy"),
        key_field: None,
        str_key_field: None,
        fields,
        is_dynamic: true,
    };
    let mut data_map = types::OwnedMap::new();
    data_map.insert("id", OwnedValue::I64(100));
    data_map.insert("score", OwnedValue::U64(70));
    data_map.insert("name", OwnedValue::String(String::from("Jack")));
    data_map.insert("year", OwnedValue::U16(2010));
    data_map.insert("major", OwnedValue::String(String::from("CS")));
    let mut data = OwnedValue::Map(data_map);
    let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
    chunk.meta.schemas.new_schema(schema.clone());
    let mut cell = OwnedCell {
        header: CellHeader::new(0, schema.id, &id1),
        data,
    };
    let mut loc = chunk.write_cell_to_chunk(&mut cell);
    let cell_1_ptr = loc.unwrap().0;
    {
        let stored_cell = SharedCellData::from_chunk_raw(cell_1_ptr, &chunk)
            .unwrap()
            .0;
        assert!(stored_cell.header.size > (4 + CELL_HEADER_SIZE) as u32);
        assert!(stored_cell.header.size > (4 + CELL_HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
        assert_eq!(stored_cell.data["year"].u16().unwrap(), &2010);
        assert_eq!(stored_cell.data["major"].string().unwrap(), "CS");
    }

    data_map = types::OwnedMap::new();
    data_map.insert("id", OwnedValue::I64(2));
    data_map.insert("score", OwnedValue::U64(80));
    data_map.insert("name", OwnedValue::String(String::from("John")));
    data = OwnedValue::Map(data_map);
    cell = OwnedCell {
        header: CellHeader::new(0, schema.id, &id2),
        data,
    };
    loc = chunk.write_cell_to_chunk(&mut cell);
    let cell_2_ptr = loc.unwrap().0;
    {
        let stored_cell = SharedCellData::from_chunk_raw(cell_2_ptr, &chunk)
            .unwrap()
            .0;
        assert!(stored_cell.header.size > (4 + CELL_HEADER_SIZE) as u32);
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &80);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
        assert!(stored_cell.data["major"].string().is_none());
    }
}
<commit_msg>fix test case<commit_after>use crate::ram::cell::*;
use crate::ram::chunk::Chunks;
use crate::ram::schema::*;
use crate::ram::types;
use crate::ram::types::*;

use super::*;

pub const CHUNK_SIZE: usize = 8 * 1024 * 1024;

#[cfg(feature = "fast_map")]
#[test]
pub fn cell_rw() {
    let fields = default_fields();
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let schema = Schema {
        id: 1,
        name: String::from("dummy"),
        key_field: None,
        str_key_field: None,
        fields,
        is_dynamic: false,
    };
    let mut data = data_map_value! {
        id: 100 as i64,
        score: 70 as u64,
        name: String::from("Jack")
    };
    let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
    chunk.meta.schemas.new_schema(schema.clone());
    let mut cell = OwnedCell {
        header: CellHeader::new(0, schema.id, &id1),
        data,
    };
    let mut loc = chunk.write_cell_to_chunk(&mut cell);
    let cell_1_ptr = loc.unwrap().0;
    {
        let (stored_cell, _) = SharedCellData::from_chunk_raw(cell_1_ptr, &chunk).unwrap();
        assert_eq!(stored_cell.header.size, 24);
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
    data = data_map_value! {
        id: 2 as i64,
        score: 80 as u64,
        name: "John"
    };
    cell = OwnedCell {
        header: CellHeader::new(0, schema.id, &id2),
        data,
    };
    loc = chunk.write_cell_to_chunk(&mut cell);
    let cell_2_ptr = loc.unwrap().0;

    assert_eq!(cell_2_ptr, cell_1_ptr + cell.header.size as usize);
    {
        let stored_cell = SharedCellData::from_chunk_raw(cell_2_ptr, &chunk)
            .unwrap()
            .0;
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &80);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
    }
    {
        let stored_cell = SharedCellData::from_chunk_raw(cell_1_ptr, &chunk)
            .unwrap()
            .0;
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
    }
}

#[cfg(feature = "fast_map")]
#[test]
pub fn dynamic() {
    let fields = default_fields();
    let id1 = Id::new(1, 1);
    let id2 = Id::new(1, 2);
    let schema = Schema {
        id: 1,
        name: String::from("dummy"),
        key_field: None,
        str_key_field: None,
        fields,
        is_dynamic: true,
    };
    let mut data_map = types::OwnedMap::new();
    data_map.insert("id", OwnedValue::I64(100));
    data_map.insert("score", OwnedValue::U64(70));
    data_map.insert("name", OwnedValue::String(String::from("Jack")));
    data_map.insert("year", OwnedValue::U16(2010));
    data_map.insert("major", OwnedValue::String(String::from("CS")));
    let mut data = OwnedValue::Map(data_map);
    let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
    chunk.meta.schemas.new_schema(schema.clone());
    let mut cell = OwnedCell {
        header: CellHeader::new(0, schema.id, &id1),
        data,
    };
    let mut loc = chunk.write_cell_to_chunk(&mut cell);
    let cell_1_ptr = loc.unwrap().0;
    {
        let stored_cell = SharedCellData::from_chunk_raw(cell_1_ptr, &chunk)
            .unwrap()
            .0;
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &100);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "Jack");
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &70);
        assert_eq!(stored_cell.data["year"].u16().unwrap(), &2010);
        assert_eq!(stored_cell.data["major"].string().unwrap(), "CS");
        assert!(stored_cell.header.size > (4 + CELL_HEADER_SIZE) as u32);
    }

    data_map = types::OwnedMap::new();
    data_map.insert("id", OwnedValue::I64(2));
    data_map.insert("score", OwnedValue::U64(80));
    data_map.insert("name", OwnedValue::String(String::from("John")));
    data = OwnedValue::Map(data_map);
    cell = OwnedCell {
        header: CellHeader::new(0, schema.id, &id2),
        data,
    };
    loc = chunk.write_cell_to_chunk(&mut cell);
    let cell_2_ptr = loc.unwrap().0;
    {
        let stored_cell = SharedCellData::from_chunk_raw(cell_2_ptr, &chunk)
            .unwrap()
            .0;
        assert_eq!(stored_cell.data["id"].i64().unwrap(), &2);
        assert_eq!(stored_cell.data["score"].u64().unwrap(), &80);
        assert_eq!(stored_cell.data["name"].string().unwrap(), "John");
        assert!(stored_cell.data["major"].string().is_none());
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Read_a_file_line_by_line

#[cfg(not(test))]
use std::io::fs::File;
#[cfg(not(test))]
use std::io::BufferedReader;
#[cfg(not(test))]
use std::os::args;

#[cfg(not(test))]
fn main() {
    let filename = match args().len() {
        1 => fail!("You must enter a filename to read line by line"),
        _ => args()[1]
    };

    let file = File::open(&Path::new(filename));
    let mut reader = BufferedReader::new(file);

    for line in reader.lines() {
        // Handle any errors that may arise
        match line {
            Ok(ln) => print!("{}", ln),
            Err(error) => print!("{}", error.desc)
        }
    }

    println!("");
}
<commit_msg>fix read_file_lines<commit_after>// Implements http://rosettacode.org/wiki/Read_a_file_line_by_line
#![cfg(not_tested)]

use std::io::fs::File;
use std::io::BufferedReader;
use std::os::args;

fn main() {
    let filename = match args().len() {
        1 => fail!("You must enter a filename to read line by line"),
        _ => args().get(1).clone()
    };

    let file = File::open(&Path::new(filename.as_slice()));
    let mut reader = BufferedReader::new(file);

    for line in reader.lines() {
        // Handle any errors that may arise
        match line {
            Ok(ln) => print!("{}", ln),
            Err(error) => print!("{}", error.desc)
        }
    }

    println!("");
}
<|endoftext|>


<commit_before>use backend::Backend;
use query_builder::*;
use result::QueryResult;
use super::Expression;
use types::BigInt;

/// Creates a SQL `COUNT` expression
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically as `diesel::dsl::count`, or glob import
/// `diesel::dsl::*`
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// # use diesel::dsl::*;
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::animals::dsl::*;
/// #     let connection = establish_connection();
/// assert_eq!(Ok(1), animals.select(count(name)).first(&connection));
/// # }
/// ```
pub fn count<T: Expression>(t: T) -> Count<T> {
    Count { target: t }
}

/// Creates a SQL `COUNT(*)` expression
///
/// For selecting the count of a query, and nothing else, you can just call
/// [`count`](https://docs.diesel.rs/diesel/prelude/trait.CountDsl.html#method.count)
/// on the query instead.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically as `diesel::dsl::count_star`, or glob import
/// `diesel::dsl::*`
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// # use diesel::dsl::*;
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// assert_eq!(Ok(2), users.select(count_star()).first(&connection));
/// # }
/// ```
pub fn count_star() -> CountStar {
    CountStar
}

#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct Count<T> {
    target: T,
}

impl<T: Expression> Expression for Count<T> {
    type SqlType = BigInt;
}

impl<T: QueryFragment<DB>, DB: Backend> QueryFragment<DB> for Count<T> {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("COUNT(");
        self.target.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl_query_id!(Count<T>);
impl_selectable_expression!(Count<T>);

#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CountStar;

impl Expression for CountStar {
    type SqlType = BigInt;
}

impl<DB: Backend> QueryFragment<DB> for CountStar {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("COUNT(*)");
        Ok(())
    }
}

impl_query_id!(CountStar);
impl_selectable_expression!(CountStar);
<commit_msg>Docs: Fix path to CountDsl::count<commit_after>use backend::Backend;
use query_builder::*;
use result::QueryResult;
use super::Expression;
use types::BigInt;

/// Creates a SQL `COUNT` expression
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically as `diesel::dsl::count`, or glob import
/// `diesel::dsl::*`
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// # use diesel::dsl::*;
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::animals::dsl::*;
/// #     let connection = establish_connection();
/// assert_eq!(Ok(1), animals.select(count(name)).first(&connection));
/// # }
/// ```
pub fn count<T: Expression>(t: T) -> Count<T> {
    Count { target: t }
}

/// Creates a SQL `COUNT(*)` expression
///
/// For selecting the count of a query, and nothing else, you can just call
/// [`count`](../query_dsl/trait.CountDsl.html#method.count)
/// on the query instead.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically as `diesel::dsl::count_star`, or glob import
/// `diesel::dsl::*`
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// # use diesel::dsl::*;
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// assert_eq!(Ok(2), users.select(count_star()).first(&connection));
/// # }
/// ```
pub fn count_star() -> CountStar {
    CountStar
}

#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct Count<T> {
    target: T,
}

impl<T: Expression> Expression for Count<T> {
    type SqlType = BigInt;
}

impl<T: QueryFragment<DB>, DB: Backend> QueryFragment<DB> for Count<T> {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("COUNT(");
        self.target.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl_query_id!(Count<T>);
impl_selectable_expression!(Count<T>);

#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CountStar;

impl Expression for CountStar {
    type SqlType = BigInt;
}

impl<DB: Backend> QueryFragment<DB> for CountStar {
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("COUNT(*)");
        Ok(())
    }
}

impl_query_id!(CountStar);
impl_selectable_expression!(CountStar);
<|endoftext|>


<commit_before>use std::libc::{
    c_char,
    c_int,
    c_uint,
    c_ulong,
    c_void,
    mode_t,
    off_t,
    pid_t,
    size_t,
    stat,
    uid_t,
    gid_t
};

mod fuse;

/// Information to be returned from open
#[deriving(Zero)]
pub struct OpenReply {
    direct_io:bool,
    keep_cache:bool,
    fh: u64
}

pub struct ReadReply;

macro_rules! declare_fuse_llops(
    ({$($name:ident : ($($pname:ident : $ptype:ty),*) -> $rt:ty),* }) => (

pub struct FuseLowLevelOps {
    init: Option<~fn()>,
    destroy: Option<~fn()>,
    forget: Option<~fn(ino:fuse::fuse_ino_t, nlookup:c_ulong)>,
    $($name : Option<~fn($($pname: $ptype),*) -> Result<$rt, c_int>>),*
}
)
)

declare_fuse_llops!({
        lookup: (parent:fuse::fuse_ino_t,name:&str) -> fuse::Struct_fuse_entry_param,
        getattr: (ino: fuse::fuse_ino_t, flags:c_int) -> OpenReply,
        read: (ino: fuse::fuse_ino_t, size: size_t, off: off_t, fh: u64)-> ReadReply
    })

pub fn fllo() -> FuseLowLevelOps {
    FuseLowLevelOps { init: None, destroy: None, forget: None, lookup: None,
        getattr: None, read: None }
}
<commit_msg>Thin interface compiles...with a lot of TODOs<commit_after>use std::libc::{
    c_char,
    c_double,
    c_int,
    c_uint,
    c_ulong,
    c_void,
    dev_t,
    gid_t,
    mode_t,
    off_t,
    pid_t,
    size_t,
    stat,
    time_t,
    uid_t,
};
use fuse::*;
use statvfs::Struct_statvfs;

mod fuse;
mod statvfs;

/// Information to be returned from open
#[deriving(Zero)]
pub struct OpenReply {
    direct_io:bool,
    keep_cache:bool,
    fh: u64
}

pub struct AttrReply {
    attr: stat,
    attr_timeout: c_double
}

pub struct EntryReply {
    ino: fuse_ino_t,
    generation: c_ulong,
    attr: stat,
    attr_timeout: c_double,
    entry_timeout: c_double
}

pub enum AttrToSet {
    Mode(mode_t),
    Uid(uid_t),
    Gid(gid_t),
    Size(size_t),
    Atime(time_t),
    Mtime(time_t),

    // TODO: confirm assumption about what these mean
    Atime_now,
    Mtime_now,
}

pub enum ReadReply {
    // TODO: support iov and fuse_bufvec type replies for more efficient (?)
    // types of implementation
    DataBuffer(~[u8])
}

type ErrnoResult<T> = Result<T, c_int>;

/** Struct full of optional functions to implement fuse operations
 *
 * This really should be a trait.  But we can't know at run time which default
 * methods of a trait were overridden, which means we don't know which entries
 * in the Struct_fuse_lowlevel_ops to null out.  FUSE has default behavior for
 * some ops that can't just be invoked from a callback--the only way to get it
 * is to pass NULL for the callback pointers.  So here it is--a struct full of
 * optional closures instead. Argh.
 */
#[deriving(Zero)]
pub struct FuseLowLevelOps {
    init: Option<~fn()>,
    destroy: Option<~fn()>,
    lookup: Option<~fn(parent: fuse::fuse_ino_t, name: &str)
                       -> ErrnoResult<fuse::Struct_fuse_entry_param>>,
    forget: Option<~fn(ino:fuse::fuse_ino_t, nlookup:c_ulong)>,
    getattr: Option<~fn(ino: fuse::fuse_ino_t, flags: c_int)
                        -> ErrnoResult<AttrReply>>,
    setattr: Option<~fn(ino: fuse_ino_t, attrs_to_set:&[AttrToSet],
                        fh:Option<u64>) -> ErrnoResult<AttrReply>>,
    readlink:Option<~fn(fuse_ino_t) -> ErrnoResult<~str>>,
    mknod: Option<~fn(parent: fuse_ino_t, name: &str, mode: mode_t,
                      rdev: dev_t) -> ErrnoResult<EntryReply>>,
    mkdir: Option<~fn(parent: fuse_ino_t, name: &str, mode: mode_t)
        -> ErrnoResult<EntryReply>>,
    // TODO: Using the unit type with result seems kind of goofy, but
    // is done for consistency with the others.  Is this right?
    unlink: Option<~fn(parent: fuse_ino_t, name: &str)
        -> ErrnoResult<()>>,
    rmdir: Option<~fn(parent: fuse_ino_t, name: &str)
        -> ErrnoResult<()>>,
    symlink: Option<~fn(link:&str, parent: fuse_ino_t, name: &str)
        -> ErrnoResult<EntryReply>>,
    rename: Option<~fn(parent: fuse_ino_t, name: &str,
                       newparent: fuse_ino_t, newname: &str)
        -> ErrnoResult<()>>,
    link: Option<~fn(ino: fuse_ino_t, newparent: fuse_ino_t, newname: &str)
        -> ErrnoResult<EntryReply>>,
    open: Option<~fn(ino: fuse_ino_t, flags: c_int)
        -> ErrnoResult<OpenReply>>,
    read: Option<~fn(ino: fuse::fuse_ino_t, size: size_t, off: off_t, fh: u64)
                     -> ErrnoResult<ReadReply>>,
    // TODO: is writepage a bool, or an actual number that needs to be
    // preserved?
    write: Option<~fn(ino: fuse_ino_t, buf:&[u8], off: off_t, fh: u64,
                      writepage: bool) -> ErrnoResult<size_t>>,
    flush: Option<~fn(ino: fuse_ino_t, lock_owner: u64, fh: u64)
        -> ErrnoResult<()>>,
    release: Option<~fn(ino: fuse_ino_t, flags: c_int, fh: u64)
        -> ErrnoResult<()>>,
    fsync: Option<~fn(ino: fuse_ino_t, datasync: bool, fh: u64)
        -> ErrnoResult<()>>,
    opendir: Option<~fn(ino: fuse_ino_t) -> ErrnoResult<OpenReply>>,
    // TODO: Using a ReadReply would require the impl to do unsafe operations
    // to use fuse_add_direntry.  So even the thin interface needs something
    // else here.
    readdir: Option<~fn(ino: fuse_ino_t, size: size_t, off: off_t, fh: u64)
        -> ErrnoResult<ReadReply>>,
    releasedir: Option<~fn(ino: fuse_ino_t, fh: u64) -> ErrnoResult<()>>,
    fsyncdir: Option<~fn(ino: fuse_ino_t, datasync: bool, fh: u64)
        -> ErrnoResult<()>>,
    statfs: Option<~fn(ino: fuse_ino_t) -> ErrnoResult<Struct_statvfs>>,
    setxattr: Option<~fn(ino: fuse_ino_t, name: &str, value: &[u8], flags: int)
        -> ErrnoResult<()>>,
    // TODO: examine this--ReadReply may not be appropraite here
    getxattr: Option<~fn(ino: fuse_ino_t, name: &str, size: size_t)
        -> ErrnoResult<ReadReply>>,
    // Called on getxattr with size of zero (meaning a query of total size)
    getxattr_size: Option<~fn(ino: fuse_ino_t, name: &str)
        -> ErrnoResult<size_t>>,
    // TODO: examine this--ReadReply may not be appropraite here
    listxattr: Option<~fn(ino: fuse_ino_t, name: &str, size: size_t)
        -> ErrnoResult<ReadReply>>,
    // Called on listxattr with size of zero (meaning a query of total size)
    listxattr_size: Option<~fn(ino: fuse_ino_t, name: &str)
        -> ErrnoResult<size_t>>,
    removexattr: Option<~fn(ino: fuse_ino_t, name: &str) -> ErrnoResult<()>>,
    access: Option<~fn(ino: fuse_ino_t, mask: c_int) -> ErrnoResult<()>>,
    create: Option<~fn(ino: fuse_ino_t, parent: fuse_ino_t, name: &str,
                       mode: mode_t, flags: c_int) -> ErrnoResult<OpenReply>>,

    // TODO: The following, which didn't even exist in earlier versions of FUSE,
    // can be considered nice-to-have (to an even greater extent than the whole
    // project can at this point):
    //
    // getlk
    // setlk
    // bmap
    // ioctl
    // poll
    // write_buf
    // retrieve_reply
    // forget_multi
    // flock
    // fallocate
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::io::{self, Cursor, Read};
use std::marker::PhantomData;
use std::mem;

use crate::color::ColorType;
use crate::image::ImageDecoder;
use crate::error::{ImageError, ImageResult};

/// JPEG decoder
pub struct JpegDecoder<R> {
    decoder: jpeg::Decoder<R>,
    metadata: jpeg::ImageInfo,
}

impl<R: Read> JpegDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(r: R) -> ImageResult<JpegDecoder<R>> {
        let mut decoder = jpeg::Decoder::new(r);

        decoder.read_info().map_err(ImageError::from_jpeg)?;
        let mut metadata = decoder.info().unwrap();

        // We convert CMYK data to RGB before returning it to the user.
        if metadata.pixel_format == jpeg::PixelFormat::CMYK32 {
            metadata.pixel_format = jpeg::PixelFormat::RGB24;
        }

        Ok(JpegDecoder {
            decoder,
            metadata,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct JpegReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for JpegReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for JpegDecoder<R> {
    type Reader = JpegReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (u32::from(self.metadata.width), u32::from(self.metadata.height))
    }

    fn color_type(&self) -> ColorType {
        ColorType::from_jpeg(self.metadata.pixel_format)
    }

    fn into_reader(mut self) -> ImageResult<Self::Reader> {
        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        Ok(JpegReader(Cursor::new(data), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        buf.copy_from_slice(&data);
        Ok(())
    }
}

fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
    let size = input.len() - input.len() / 4;
    let mut output = Vec::with_capacity(size);

    let inv = 1.0 / 255.0;
    for pixel in input.chunks(4) {
        let c = f32::from(pixel[0]);
        let m = f32::from(pixel[1]);
        let y = f32::from(pixel[2]);
        let k = 255.0 - f32::from(pixel[3]);

        let k_mul = k * 255.0;
        // CMY -> RGB
        let r = (k_mul - c * k) * inv;
        let g = (k_mul - m * k) * inv;
        let b = (k_mul - y * k) * inv;

        output.push(r as u8);
        output.push(g as u8);
        output.push(b as u8);
    }

    output
}

impl ColorType {
    fn from_jpeg(pixel_format: jpeg::PixelFormat) -> ColorType {
        use jpeg::PixelFormat::*;
        match pixel_format {
            L8 => ColorType::L8,
            RGB24 => ColorType::Rgb8,
            CMYK32 => panic!(),
        }
    }
}

impl ImageError {
    fn from_jpeg(err: jpeg::Error) -> ImageError {
        use jpeg::Error::*;
        match err {
            Format(desc) => ImageError::FormatError(desc),
            Unsupported(desc) => ImageError::UnsupportedError(format!("{:?}", desc)),
            Io(err) => ImageError::IoError(err),
            Internal(err) => ImageError::FormatError(err.to_string()),
        }
    }
}

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

    #[test]
    fn cymk_to_rgb_correct() {
        // Based on R = 255 * (1-C/255) * (1-K/255)
        for c in 0..255 {
            for k in 0..255 {
                let r = (255.0 - f32::from(c)) * (255.0 - f32::from(k)) / 255.0;
                let r_u8 = r as u8;
                let convert_r = cmyk_to_rgb(&[c, 0, 0, k])[0];
                assert_eq!(convert_r, r_u8,
                           "c = {}, k = {}, cymk_to_rgb[0] = {}, should be {}", c, k, convert_r, r_u8);
            }
        }
    }
}

<commit_msg>Add further optimizations to cmyk_to_rgb function, thanks to @HeroicKatora<commit_after>use std::convert::TryFrom;
use std::io::{self, Cursor, Read};
use std::marker::PhantomData;
use std::mem;

use crate::color::ColorType;
use crate::image::ImageDecoder;
use crate::error::{ImageError, ImageResult};

/// JPEG decoder
pub struct JpegDecoder<R> {
    decoder: jpeg::Decoder<R>,
    metadata: jpeg::ImageInfo,
}

impl<R: Read> JpegDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(r: R) -> ImageResult<JpegDecoder<R>> {
        let mut decoder = jpeg::Decoder::new(r);

        decoder.read_info().map_err(ImageError::from_jpeg)?;
        let mut metadata = decoder.info().unwrap();

        // We convert CMYK data to RGB before returning it to the user.
        if metadata.pixel_format == jpeg::PixelFormat::CMYK32 {
            metadata.pixel_format = jpeg::PixelFormat::RGB24;
        }

        Ok(JpegDecoder {
            decoder,
            metadata,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct JpegReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for JpegReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for JpegDecoder<R> {
    type Reader = JpegReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (u32::from(self.metadata.width), u32::from(self.metadata.height))
    }

    fn color_type(&self) -> ColorType {
        ColorType::from_jpeg(self.metadata.pixel_format)
    }

    fn into_reader(mut self) -> ImageResult<Self::Reader> {
        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        Ok(JpegReader(Cursor::new(data), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        let mut data = self.decoder.decode().map_err(ImageError::from_jpeg)?;
        data = match self.decoder.info().unwrap().pixel_format {
            jpeg::PixelFormat::CMYK32 => cmyk_to_rgb(&data),
            _ => data,
        };

        buf.copy_from_slice(&data);
        Ok(())
    }
}

pub fn cmyk_to_rgb(input: &[u8]) -> Vec<u8> {
    let count = input.len()/4;
    let mut output = vec![0; 3*count];

    let in_pixels = input[..4*count].chunks_exact(4);
    let out_pixels = output[..3*count].chunks_exact_mut(3);

    let inv = 1.0/255.0;
    for (pixel, outp) in in_pixels.zip(out_pixels) {
        let c = 255 - u16::from(pixel[0]);
        let m = 255 - u16::from(pixel[1]);
        let y = 255 - u16::from(pixel[2]);
        let k = 255 - u16::from(pixel[3]);

        // CMY -> RGB
        let r = (k * c) as f32 * inv;
        let g = (k * m) as f32 * inv;
        let b = (k * y) as f32 * inv;

        outp[0] = r as u8;
        outp[1] = g as u8;
        outp[2] = b as u8;
    }

    output
}

impl ColorType {
    fn from_jpeg(pixel_format: jpeg::PixelFormat) -> ColorType {
        use jpeg::PixelFormat::*;
        match pixel_format {
            L8 => ColorType::L8,
            RGB24 => ColorType::Rgb8,
            CMYK32 => panic!(),
        }
    }
}

impl ImageError {
    fn from_jpeg(err: jpeg::Error) -> ImageError {
        use jpeg::Error::*;
        match err {
            Format(desc) => ImageError::FormatError(desc),
            Unsupported(desc) => ImageError::UnsupportedError(format!("{:?}", desc)),
            Io(err) => ImageError::IoError(err),
            Internal(err) => ImageError::FormatError(err.to_string()),
        }
    }
}

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

    #[test]
    fn cymk_to_rgb_correct() {
        // Based on R = 255 * (1-C/255) * (1-K/255)
        for c in 0..255 {
            for k in 0..255 {
                let r = (255.0 - f32::from(c)) * (255.0 - f32::from(k)) / 255.0;
                let r_u8 = r as u8;
                let convert_r = cmyk_to_rgb(&[c, 0, 0, k])[0];
                assert_eq!(convert_r, r_u8,
                           "c = {}, k = {}, cymk_to_rgb[0] = {}, should be {}", c, k, convert_r, r_u8);
            }
        }
    }
}

<|endoftext|>


<commit_before>use game::simpleboard::SimpleBoard;
use game::board::{State, GoBoard, GoMove};
use search::evaluation::Evaluation;

pub fn minimax(board: &mut SimpleBoard, depth: i8, maximizing_player: bool) -> (f64, Option<GoMove>) {
    if depth == 0 {
        (board.evaluate(), None)
    }
    else {
        if maximizing_player {
            let player = State::Black;
            let mut best_value: f64 = -10000.0;
            // Loop over all possible moves
            let moves = board.move_list(player);
            let mut good_move = GoMove::Pass;
            for mv in moves {
                let mut new_board = board.clone();
                new_board.play_move(&mv);
                let (v, _) = minimax(&mut new_board, depth - 1, false);
                if v > best_value {
                    best_value = v;
                    good_move = mv.clone();
                }
            }
            (best_value, Some(good_move))
        }
        else {
            let player = State::White;
            let mut best_value: f64 = 10000.0;
            let moves = board.move_list(player);
            let mut good_move = GoMove::Pass;
            for mv in moves {
                let mut new_board = board.clone();
                new_board.play_move(&mv);
                let (v, _) = minimax(&mut new_board, depth - 1, true);
                if v < best_value {
                    best_value = v;
                    good_move = mv.clone();
                }
            }
            (best_value, Some(good_move))
        }
    }
}

#[cfg(test)]
mod tests {
    use game::simpleboard::SimpleBoard;
    use game::board::*;
    use search::evaluation::*;
    use super::*;

    #[test]
    fn three_space_life() {
        let mut game_board = SimpleBoard::new(6, 4);

        let black_x = vec![0, 1, 2, 3, 3];
        let black_y = vec![1, 1, 1, 1, 0];

        for (x, y) in black_x.iter().zip(black_y.iter()) {
            let mv = GoMove::Move{x: *x, y: *y, player: State::Black};
            game_board.play_move(&mv);
        }

        let white_x = vec![0, 1, 2, 3, 4, 4, 4];
        let white_y = vec![2, 2, 2, 2, 2, 1, 0];

        for (x, y) in white_x.iter().zip(white_y.iter()) {
            let mv = GoMove::Move{x: *x, y: *y, player: State::White};
            game_board.play_move(&mv);
        }

        println!("", );
        for idx in 0..5 {
            game_board.print_board();
            if idx % 2 == 0 {
                let (val, mv) = minimax(&mut game_board, 8, true);
                game_board.play_move(&mv.unwrap());
            }
            else {
                let (val, mv) = minimax(&mut game_board, 8, false);
                game_board.play_move(&mv.unwrap());
            }
            println!("", );
        }

        println!("{:?}", game_board.evaluate());
        //game_board.play_move(&GoMove::Move{x: 1, y: 0, player: State::Black});
        //println!("{:?}", game_board.evaluate());
        //game_board.print_board();

        assert_eq!(0, 1);

    }

    #[test]
    fn corner_kill() {
        let mut game_board = SimpleBoard::new(7, 5);

        let black_x = vec![0, 1, 2, 3, 4, 5, 5, 5, 2];
        let black_y = vec![3, 3, 3, 2, 2, 2, 1, 0, 0];

        for (x, y) in black_x.iter().zip(black_y.iter()) {
            let mv = GoMove::Move{x: *x, y: *y, player: State::Black};
            game_board.play_move(&mv);
        }

        let white_x = vec![0, 1, 2, 3, 4, 1];
        let white_y = vec![2, 2, 2, 1, 1, 0];

        for (x, y) in white_x.iter().zip(white_y.iter()) {
            let mv = GoMove::Move{x: *x, y: *y, player: State::White};
            game_board.play_move(&mv);
        }

        println!("", );
        for idx in 0..7 {
            game_board.print_board();
            if idx % 2 == 0 {
                let (val, mv) = minimax(&mut game_board, 7, true);
                game_board.play_move(&mv.unwrap());
            }
            else {
                let (val, mv) = minimax(&mut game_board, 7, false);
                game_board.play_move(&mv.unwrap());
            }
            println!("", );
        }
        assert_eq!(0, 1);

    }

}
<commit_msg>Updated tests<commit_after>use game::simpleboard::SimpleBoard;
use game::board::{State, GoBoard, GoMove};
use search::evaluation::Evaluation;

pub fn minimax(board: &mut SimpleBoard, depth: i8, maximizing_player: bool) -> (f64, Option<GoMove>) {
    if depth == 0 {
        (board.evaluate(), None)
    }
    else {
        if maximizing_player {
            let player = State::Black;
            let mut best_value: f64 = -10000.0;
            // Loop over all possible moves
            let moves = board.move_list(player);
            let mut good_move = GoMove::Pass;
            for mv in moves {
                let mut new_board = board.clone();
                new_board.play_move(&mv);
                let (v, _) = minimax(&mut new_board, depth - 1, false);
                if v > best_value {
                    best_value = v;
                    good_move = mv.clone();
                }
            }
            (best_value, Some(good_move))
        }
        else {
            let player = State::White;
            let mut best_value: f64 = 10000.0;
            let moves = board.move_list(player);
            let mut good_move = GoMove::Pass;
            for mv in moves {
                let mut new_board = board.clone();
                new_board.play_move(&mv);
                let (v, _) = minimax(&mut new_board, depth - 1, true);
                if v < best_value {
                    best_value = v;
                    good_move = mv.clone();
                }
            }
            (best_value, Some(good_move))
        }
    }
}

#[cfg(test)]
mod tests {
    use game::simpleboard::SimpleBoard;
    use game::board::*;
    use super::*;

    #[test]
    fn three_space_life() {
        let mut game_board = SimpleBoard::new(6, 4);

        let black_x = vec![0, 1, 2, 3, 3];
        let black_y = vec![1, 1, 1, 1, 0];

        for (x, y) in black_x.iter().zip(black_y.iter()) {
            let mv = GoMove::Move{x: *x, y: *y, player: State::Black};
            game_board.play_move(&mv);
        }

        let white_x = vec![0, 1, 2, 3, 4, 4, 4];
        let white_y = vec![2, 2, 2, 2, 2, 1, 0];

        for (x, y) in white_x.iter().zip(white_y.iter()) {
            let mv = GoMove::Move{x: *x, y: *y, player: State::White};
            game_board.play_move(&mv);
        }

        let (_, mv) = minimax(&mut game_board, 8, true);

        assert_eq!(mv.unwrap(), GoMove::Move{x: 1, y: 0, player: State::Black});
    }

    #[test]
    fn corner_kill() {
        let mut game_board = SimpleBoard::new(7, 5);

        let black_x = vec![0, 1, 2, 3, 4, 5, 5, 5, 2];
        let black_y = vec![3, 3, 3, 2, 2, 2, 1, 0, 0];

        for (x, y) in black_x.iter().zip(black_y.iter()) {
            let mv = GoMove::Move{x: *x, y: *y, player: State::Black};
            game_board.play_move(&mv);
        }

        let white_x = vec![0, 1, 2, 3, 4, 1];
        let white_y = vec![2, 2, 2, 1, 1, 0];

        for (x, y) in white_x.iter().zip(white_y.iter()) {
            let mv = GoMove::Move{x: *x, y: *y, player: State::White};
            game_board.play_move(&mv);
        }
        let (_, mv) = minimax(&mut game_board, 7, true);
        assert_eq!(mv.unwrap(), GoMove::Move{x: 0, y: 0, player: State::Black});
    }

}
<|endoftext|>


<commit_before>extern crate encoding;
extern crate getopts;

use std::env;
use std::io::{Read, Write};
use std::net::TcpStream;
use getopts::Options;
use encoding::{Encoding, EncoderTrap, DecoderTrap};
use encoding::all::{ASCII, EUC_JP};

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optopt("h", "host", "Host to connect", "ADDR");
    opts.optopt("p", "port", "Port to connect", "PORT");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()); }
    };
    let host = matches.opt_str("h").unwrap_or("127.0.0.1".to_string());
    let port = matches.opt_str("p").unwrap_or("1178".to_string()).parse::<u16>().unwrap();
    let default_kana = "a".to_string();
    let kana = matches.free.first().unwrap_or(&default_kana);

    println!("Connecting {}:{}", host, port);
    let mut stream = TcpStream::connect((&*host, port)).unwrap();
    let encoding = EUC_JP;

    let version = get_version(&mut stream, encoding).unwrap();
    println!("Version: {}", version);

    let candidate = get_candidate(&mut stream, &kana, encoding).unwrap();
    println!("{}", kana);
    println!("{}", candidate);

    let _ = disconnect(&mut stream).unwrap();
}

fn get_version<T: Read + Write>(stream: &mut T, encoding: &Encoding) -> std::io::Result<String> {
    try!(write_with_encoding(stream, "2", ASCII));
    try!(stream.flush());
    return read_with_encoding(stream, encoding);
}

fn disconnect<T: Write>(stream: &mut T) -> std::io::Result<()> {
    try!(write_with_encoding(stream, "0", ASCII));
    try!(stream.flush());
    return Ok(());
}

fn get_candidate<T: Read + Write>(stream: &mut T, kana: &str, encoding: &Encoding) -> std::io::Result<String> {
    try!(write_with_encoding(stream, "1", ASCII));
    try!(write_with_encoding(stream, kana, encoding));
    try!(write_with_encoding(stream, " ", ASCII));
    try!(stream.flush());
    return read_with_encoding(stream, encoding);
}

fn write_with_encoding(stream: &mut Write, input: &str, encoding: &Encoding) -> std::io::Result<usize> {
    return stream.write(&encoding.encode(input, EncoderTrap::Strict).unwrap());
}

fn read_with_encoding(stream: &mut Read, encoding: &Encoding) -> std::io::Result<String> {
    let mut buf = [0; 1024];
    let r = try!(stream.read(&mut buf));
    return Ok(encoding.decode(&buf[0 .. r-1], DecoderTrap::Strict).unwrap());
}
<commit_msg>Fix off-by-one error<commit_after>extern crate encoding;
extern crate getopts;

use std::env;
use std::io::{Read, Write};
use std::net::TcpStream;
use getopts::Options;
use encoding::{Encoding, EncoderTrap, DecoderTrap};
use encoding::all::{ASCII, EUC_JP};

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();
    opts.optopt("h", "host", "Host to connect", "ADDR");
    opts.optopt("p", "port", "Port to connect", "PORT");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()); }
    };
    let host = matches.opt_str("h").unwrap_or("127.0.0.1".to_string());
    let port = matches.opt_str("p").unwrap_or("1178".to_string()).parse::<u16>().unwrap();
    let default_kana = "a".to_string();
    let kana = matches.free.first().unwrap_or(&default_kana);

    println!("Connecting {}:{}", host, port);
    let mut stream = TcpStream::connect((&*host, port)).unwrap();
    let encoding = EUC_JP;

    let version = get_version(&mut stream, encoding).unwrap();
    println!("Version: {}", version);

    let candidate = get_candidate(&mut stream, &kana, encoding).unwrap();
    println!("{}", kana);
    println!("{}", candidate);

    let _ = disconnect(&mut stream).unwrap();
}

fn get_version<T: Read + Write>(stream: &mut T, encoding: &Encoding) -> std::io::Result<String> {
    try!(write_with_encoding(stream, "2", ASCII));
    try!(stream.flush());
    return read_with_encoding(stream, encoding);
}

fn disconnect<T: Write>(stream: &mut T) -> std::io::Result<()> {
    try!(write_with_encoding(stream, "0", ASCII));
    try!(stream.flush());
    return Ok(());
}

fn get_candidate<T: Read + Write>(stream: &mut T, kana: &str, encoding: &Encoding) -> std::io::Result<String> {
    try!(write_with_encoding(stream, "1", ASCII));
    try!(write_with_encoding(stream, kana, encoding));
    try!(write_with_encoding(stream, " ", ASCII));
    try!(stream.flush());
    return read_with_encoding(stream, encoding);
}

fn write_with_encoding(stream: &mut Write, input: &str, encoding: &Encoding) -> std::io::Result<usize> {
    return stream.write(&encoding.encode(input, EncoderTrap::Strict).unwrap());
}

fn read_with_encoding(stream: &mut Read, encoding: &Encoding) -> std::io::Result<String> {
    let mut buf = [0; 1024];
    let r = try!(stream.read(&mut buf));
    return Ok(encoding.decode(&buf[0 .. r], DecoderTrap::Strict).unwrap());
}
<|endoftext|>