<commit_before>#![feature(catch_panic, fnbox)]

//! Work-stealing job-queue implementation.
//! Inspired by the Molecular Matters blog posts.

extern crate crossbeam;
extern crate rand;

use crossbeam::sync::TreiberStack;

use std::any::Any;
use std::boxed::FnBox;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use std::thread;

use ::rand::thread_rng;
use ::rand::distributions::{IndependentSample, Range};

/// Messages that can be sent to workers.
enum WorkerMessage {
    Stop,
}

type Job = Box<FnBox(&Worker) + 'static + Send>;

/// A job's id in the pool.
pub struct JobId {
    idx: usize,
}

struct PoolEntry {
    job: Job,
    sender: Sender<JobExitStatus>,
}

enum JobExitStatus {
    Success,
    Panic(Box<Any>),
}

/// A mostly lock-free pool allocator of jobs.
/// It only locks when doubling the size of the vector.
/// Eventually, I may implement a lock-free vector based off of
/// Stroustroup-et-al's paper on the subject, but for now, I've
/// decided to "keep it simple, stupid".
struct JobPool {
    jobs: RwLock<Vec<RefCell<Option<PoolEntry>>>>,
    unused: TreiberStack<usize>,
}

impl JobPool {
    /// Initialize this pool with the given capacity.
    fn with_capacity(size: usize) -> Self {
        let mut v = Vec::with_capacity(size);
        let unused = TreiberStack::new();

        for i in (0..size).rev() {
            v.push(RefCell::new(None));

            unused.push(i);
        }

        JobPool {
            jobs: RwLock::new(v),
            unused: unused,
        }
    }

    /// Submit a job to be allocated in the pool.
    fn submit(&self, job: Job) -> (JobId, Receiver<JobExitStatus>) {
        let next = if let Some(next) = self.unused.pop() {
            next
        } else {
            self.double();
            self.unused.pop().unwrap()
        };

        let jobs = match self.jobs.read() {
            Ok(j) => j,
            Err(p) => p.into_inner(),
        };

        let (tx, rx) = channel();

        let entry = &jobs[next];
        *entry.borrow_mut() = Some(PoolEntry {
            job: job,
            sender: tx,
        });

        (JobId { idx: next, }, rx)
    }

    // double the vector
    fn double(&self) {
        let mut jobs = match self.jobs.write() {
            Ok(j) => j,
            Err(p) => p.into_inner(),
        };

        let old_len = jobs.len();
        let new_len = old_len * 2;

        jobs.reserve(new_len);

        for i in (old_len..new_len).rev() {
            jobs.push(RefCell::new(None));

            self.unused.push(i);
        }
    }

    /// Get the job given by id. This function should
    /// always yield Some if you use the id you are given.
    fn run(&self, id: JobId, worker: &Worker) {
        use std::mem;

        let jobs = match self.jobs.read() {
            Ok(j) => j,
            Err(p) => p.into_inner(),
        };

        // take the job out before pushing the index back onto
        // the unused stack.
        let entry = jobs[id.idx].borrow_mut().take().unwrap();

        let PoolEntry { job, sender } = entry;

        let unbounded_fn: Box<FnBox() + Send> = Box::new(move || job.call_box((worker,)));
        let bounded_fn: Box<FnBox() + 'static + Send> = unsafe { mem::transmute(unbounded_fn) };

        let exit_status = match thread::catch_panic(|| bounded_fn()) {
            Ok(_) => { JobExitStatus::Success }
            Err(e) => { JobExitStatus::Panic(e) }
        };

        // We don't really care if they receive it or not.
        let _result = sender.send(exit_status);
        self.unused.push(id.idx);
    }
}

unsafe impl Send for JobPool {}
unsafe impl Sync for JobPool {}

/// A thread-safe double-ended queue for jobs.
/// Right now, it's just a dumb locking wrapper of VecDeque.
/// It stores indices of jobs in the global job pool.
struct JobQueue {
    inner: Mutex<VecDeque<JobId>>,
}

impl JobQueue {
    fn new() -> Self {
        JobQueue {
            inner: Mutex::new(VecDeque::new()),
        }
    }

    // pop a job from the private end of the queue.
    // only the owner of this queue should call this.
    fn pop(&self) -> Option<JobId> {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.pop_back()
    }

    // steal a job from the public end of the queue.
    fn steal(&self) -> Option<JobId> {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.pop_front()
    }

    // push another job to the queue.
    fn push(&self, job: JobId) {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.push_back(job);
    }
}

unsafe impl Send for JobQueue {}
unsafe impl Sync for JobQueue {}

/// A worker executes jobs.
pub struct Worker {
    pool: Arc<JobPool>,
    queue: Arc<JobQueue>,
    siblings: Box<[Arc<JobQueue>]>,
}

impl Worker {
    pub fn submit<F: FnOnce(&Worker) + 'static + Send>(&self, f: F) -> JoinHandle {
        let job = Box::new(f);
        let (id, notifier) = self.pool.submit(job);
        self.queue.push(id);

        JoinHandle {
            notifier: notifier,
            worker: Some(self),
        }
    }

    fn next_job(&self) -> Option<JobId> {
        if let Some(id) = self.queue.pop() {
            Some(id)
        } else {
            let mut rng = thread_rng();
            let idx = Range::new(0, self.siblings.len()).ind_sample(&mut rng);
            let other_queue: &Arc<JobQueue> = &self.siblings[idx];

            // make sure we don't steal from our own queue.
            if &*self.queue as *const JobQueue != &**other_queue as *const JobQueue {
                other_queue.steal()
            } else {
                None
            }
        }
    }

    fn run_job(&self) {
        if let Some(id) = self.next_job() {
            self.pool.run(id, self);
        }
    }

    // run this worker to completion.
    fn run_to_completion(&self) {
        while let Some(id) = self.queue.pop() {
            self.pool.run(id, self);
        }

        // help run all the sibling queues to completion as well.
        for sibling in self.siblings.iter() {
            while let Some(id) = sibling.steal() {
                self.pool.run(id, self);
            }
        }
    }
}

/// A JoinHandle can be used to manually wait for
/// a job to be completed.
pub struct JoinHandle<'a> {
    notifier: Receiver<JobExitStatus>,
    worker: Option<&'a Worker>,
}

impl<'a> JoinHandle<'a> {
    pub fn wait(self) -> Result<(), Box<Any>> {
        loop {
            match self.notifier.try_recv() {
                Ok(exit_status) => {
                    return match exit_status {
                        JobExitStatus::Success => Ok(()),
                        JobExitStatus::Panic(err) => Err(err),
                    }
                }

                // sender _never_ hangs up before the job is done.
                Err(TryRecvError::Disconnected) => unreachable!(),

                // nothing yet, just do some more work.
                _ => {
                    if let &Some(ref worker) = &self.worker {
                        worker.run_job()
                    }
                }
            }
        }
    }
}

pub struct JobSystem {
    handles: Vec<Sender<WorkerMessage>>,
    pool: Arc<JobPool>,
    queue: Arc<JobQueue>,
}

impl JobSystem {
    pub fn submit<F: FnOnce(&Worker) + 'static + Send>(&self, f: F) -> JoinHandle {
        let job = Box::new(f);
        let (id, notifier) = self.pool.submit(job);
        self.queue.push(id);

        JoinHandle {
            notifier: notifier,
            worker: None,
        }
    }
}

impl Drop for JobSystem {
    fn drop(&mut self) {
        for handle in &self.handles {
            match handle.send(WorkerMessage::Stop) {
                _ => {}
            }
        }
    }
}

/// Create a new `JobSystem` with `n_threads` worker threads.
/// This will fail if `n_threads` is less than 1.
pub fn make_pool(n_threads: usize) -> Option<JobSystem> {
    if n_threads < 1 {
        return None;
    }

    let job_pool = Arc::new(JobPool::with_capacity(4096));

    // make a queue for every thread, including this one.
    let queues: Vec<_> = (0..n_threads+1)
        .map(|_| Arc::new(JobQueue::new())).collect();

    let queues = queues.into_boxed_slice();

    let mut handles = Vec::new();

    // Spawn a worker thread for every queue but the last one,
    // since that belongs to the thread this is spawned on.
    for queue in queues.iter().cloned().take(n_threads) {
        let (tx, rx) = channel();
        let siblings = queues.clone();
        let pool = job_pool.clone();

        thread::spawn(move || {
            let worker = Worker {
                pool: pool,
                queue: queue,
                siblings: siblings,
            };

            worker_main(worker, rx);
        });
        handles.push(tx);
    }

    Some(JobSystem {
        handles: handles,
        pool: job_pool,
        queue: queues.last().unwrap().clone(),
    })
}

// the main thread for each worker
fn worker_main(worker: Worker, rx: Receiver<WorkerMessage>) {
    loop {
        // check for message
        match rx.try_recv() {
            // time to stop!
            Ok(WorkerMessage::Stop) => {
                worker.run_to_completion();
            }

            // somehow the JobSystem got dropped without disconnecting.
            Err(TryRecvError::Disconnected) => {
                worker.run_to_completion();
            }

            _ => {}
        }
        // run a job
        worker.run_job();
    }
}

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

    #[test]
    fn basic_spawning() {
        // four worker threads, including this one.
        let pool = make_pool(4).unwrap();

        for _ in 0..100 {
            pool.submit(|_| println!("Hello!"));
        }
    }

    #[test]
    fn child_jobs() {
        let pool = make_pool(4).unwrap();

        pool.submit(|worker| {
            for _ in 0..100 {
                worker.submit(|_| println!("Hello!"));
            };
        }).wait().unwrap();
    }

/*    #[test]
    fn scoping() {
        let pool = make_pool(4).unwrap();
        let this_worker = pool.get_worker();
        this_worker.submit(|worker| {
            let mut v = vec![0; 256];

            worker.scope(|scope| {
                for chunk in v.chunks_mut(32) {
                    scope.submit(move |_| {
                        for i in chunk { *i += 1 }
                    });
                }
            });

            for i in v {
                assert_eq!(i, 1);
            }
        }).wait();
    }*/
}<commit_msg>Added panic safety test<commit_after>#![feature(catch_panic, fnbox)]

//! Work-stealing job-queue implementation.
//! Inspired by the Molecular Matters blog posts.

extern crate crossbeam;
extern crate rand;

use crossbeam::sync::TreiberStack;

use std::any::Any;
use std::boxed::FnBox;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use std::thread;

use ::rand::thread_rng;
use ::rand::distributions::{IndependentSample, Range};

/// Messages that can be sent to workers.
enum WorkerMessage {
    Stop,
}

type Job = Box<FnBox(&Worker) + 'static + Send>;

/// A job's id in the pool.
pub struct JobId {
    idx: usize,
}

struct PoolEntry {
    job: Job,
    sender: Sender<JobExitStatus>,
}

enum JobExitStatus {
    Success,
    Panic(Box<Any>),
}

/// A mostly lock-free pool allocator of jobs.
/// It only locks when doubling the size of the vector.
/// Eventually, I may implement a lock-free vector based off of
/// Stroustroup-et-al's paper on the subject, but for now, I've
/// decided to "keep it simple, stupid".
struct JobPool {
    jobs: RwLock<Vec<RefCell<Option<PoolEntry>>>>,
    unused: TreiberStack<usize>,
}

impl JobPool {
    /// Initialize this pool with the given capacity.
    fn with_capacity(size: usize) -> Self {
        let mut v = Vec::with_capacity(size);
        let unused = TreiberStack::new();

        for i in (0..size).rev() {
            v.push(RefCell::new(None));

            unused.push(i);
        }

        JobPool {
            jobs: RwLock::new(v),
            unused: unused,
        }
    }

    /// Submit a job to be allocated in the pool.
    fn submit(&self, job: Job) -> (JobId, Receiver<JobExitStatus>) {
        let next = if let Some(next) = self.unused.pop() {
            next
        } else {
            self.double();
            self.unused.pop().unwrap()
        };

        let jobs = match self.jobs.read() {
            Ok(j) => j,
            Err(p) => p.into_inner(),
        };

        let (tx, rx) = channel();

        let entry = &jobs[next];
        *entry.borrow_mut() = Some(PoolEntry {
            job: job,
            sender: tx,
        });

        (JobId { idx: next, }, rx)
    }

    // double the vector
    fn double(&self) {
        let mut jobs = match self.jobs.write() {
            Ok(j) => j,
            Err(p) => p.into_inner(),
        };

        let old_len = jobs.len();
        let new_len = old_len * 2;

        jobs.reserve(new_len);

        for i in (old_len..new_len).rev() {
            jobs.push(RefCell::new(None));

            self.unused.push(i);
        }
    }

    /// Get the job given by id. This function should
    /// always yield Some if you use the id you are given.
    fn run(&self, id: JobId, worker: &Worker) {
        use std::mem;

        let jobs = match self.jobs.read() {
            Ok(j) => j,
            Err(p) => p.into_inner(),
        };

        // take the job out before pushing the index back onto
        // the unused stack.
        let entry = jobs[id.idx].borrow_mut().take().unwrap();

        let PoolEntry { job, sender } = entry;

        let unbounded_fn: Box<FnBox() + Send> = Box::new(move || job.call_box((worker,)));
        let bounded_fn: Box<FnBox() + 'static + Send> = unsafe { mem::transmute(unbounded_fn) };

        let exit_status = match thread::catch_panic(|| bounded_fn()) {
            Ok(_) => { JobExitStatus::Success }
            Err(e) => { JobExitStatus::Panic(e) }
        };

        // We don't really care if they receive it or not.
        let _result = sender.send(exit_status);
        self.unused.push(id.idx);
    }
}

unsafe impl Send for JobPool {}
unsafe impl Sync for JobPool {}

/// A thread-safe double-ended queue for jobs.
/// Right now, it's just a dumb locking wrapper of VecDeque.
/// It stores indices of jobs in the global job pool.
struct JobQueue {
    inner: Mutex<VecDeque<JobId>>,
}

impl JobQueue {
    fn new() -> Self {
        JobQueue {
            inner: Mutex::new(VecDeque::new()),
        }
    }

    // pop a job from the private end of the queue.
    // only the owner of this queue should call this.
    fn pop(&self) -> Option<JobId> {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.pop_back()
    }

    // steal a job from the public end of the queue.
    fn steal(&self) -> Option<JobId> {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.pop_front()
    }

    // push another job to the queue.
    fn push(&self, job: JobId) {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.push_back(job);
    }
}

unsafe impl Send for JobQueue {}
unsafe impl Sync for JobQueue {}

/// A worker executes jobs.
pub struct Worker {
    pool: Arc<JobPool>,
    queue: Arc<JobQueue>,
    siblings: Box<[Arc<JobQueue>]>,
}

impl Worker {
    pub fn submit<F: FnOnce(&Worker) + 'static + Send>(&self, f: F) -> JoinHandle {
        let job = Box::new(f);
        let (id, notifier) = self.pool.submit(job);
        self.queue.push(id);

        JoinHandle {
            notifier: notifier,
            worker: Some(self),
        }
    }

    fn next_job(&self) -> Option<JobId> {
        if let Some(id) = self.queue.pop() {
            Some(id)
        } else {
            let mut rng = thread_rng();
            let idx = Range::new(0, self.siblings.len()).ind_sample(&mut rng);
            let other_queue: &Arc<JobQueue> = &self.siblings[idx];

            // make sure we don't steal from our own queue.
            if &*self.queue as *const JobQueue != &**other_queue as *const JobQueue {
                other_queue.steal()
            } else {
                None
            }
        }
    }

    fn run_job(&self) {
        if let Some(id) = self.next_job() {
            self.pool.run(id, self);
        }
    }

    // run this worker to completion.
    fn run_to_completion(&self) {
        while let Some(id) = self.queue.pop() {
            self.pool.run(id, self);
        }

        // help run all the sibling queues to completion as well.
        for sibling in self.siblings.iter() {
            while let Some(id) = sibling.steal() {
                self.pool.run(id, self);
            }
        }
    }
}

/// A JoinHandle can be used to manually wait for
/// a job to be completed.
pub struct JoinHandle<'a> {
    notifier: Receiver<JobExitStatus>,
    worker: Option<&'a Worker>,
}

impl<'a> JoinHandle<'a> {
    pub fn wait(self) -> Result<(), Box<Any>> {
        loop {
            match self.notifier.try_recv() {
                Ok(exit_status) => {
                    return match exit_status {
                        JobExitStatus::Success => Ok(()),
                        JobExitStatus::Panic(err) => Err(err),
                    }
                }

                // sender _never_ hangs up before the job is done.
                Err(TryRecvError::Disconnected) => unreachable!(),

                // nothing yet, just do some more work.
                _ => {
                    if let &Some(ref worker) = &self.worker {
                        worker.run_job()
                    }
                }
            }
        }
    }
}

pub struct JobSystem {
    handles: Vec<Sender<WorkerMessage>>,
    pool: Arc<JobPool>,
    queue: Arc<JobQueue>,
}

impl JobSystem {
    pub fn submit<F: FnOnce(&Worker) + 'static + Send>(&self, f: F) -> JoinHandle {
        let job = Box::new(f);
        let (id, notifier) = self.pool.submit(job);
        self.queue.push(id);

        JoinHandle {
            notifier: notifier,
            worker: None,
        }
    }
}

impl Drop for JobSystem {
    fn drop(&mut self) {
        for handle in &self.handles {
            match handle.send(WorkerMessage::Stop) {
                _ => {}
            }
        }
    }
}

/// Create a new `JobSystem` with `n_threads` worker threads.
/// This will fail if `n_threads` is less than 1.
pub fn make_pool(n_threads: usize) -> Option<JobSystem> {
    if n_threads < 1 {
        return None;
    }

    let job_pool = Arc::new(JobPool::with_capacity(4096));

    // make a queue for every thread, including this one.
    let queues: Vec<_> = (0..n_threads+1)
        .map(|_| Arc::new(JobQueue::new())).collect();

    let queues = queues.into_boxed_slice();

    let mut handles = Vec::new();

    // Spawn a worker thread for every queue but the last one,
    // since that belongs to the thread this is spawned on.
    for queue in queues.iter().cloned().take(n_threads) {
        let (tx, rx) = channel();
        let siblings = queues.clone();
        let pool = job_pool.clone();

        thread::spawn(move || {
            let worker = Worker {
                pool: pool,
                queue: queue,
                siblings: siblings,
            };

            worker_main(worker, rx);
        });
        handles.push(tx);
    }

    Some(JobSystem {
        handles: handles,
        pool: job_pool,
        queue: queues.last().unwrap().clone(),
    })
}

// the main thread for each worker
fn worker_main(worker: Worker, rx: Receiver<WorkerMessage>) {
    loop {
        // check for message
        match rx.try_recv() {
            // time to stop!
            Ok(WorkerMessage::Stop) => {
                worker.run_to_completion();
            }

            // somehow the JobSystem got dropped without disconnecting.
            Err(TryRecvError::Disconnected) => {
                worker.run_to_completion();
            }

            _ => {}
        }
        // run a job
        worker.run_job();
    }
}

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

    #[test]
    #[should_panic]
    fn no_zero_thread_pool() {
        make_pool(0).unwrap();
    }

    #[test]
    fn basic_spawning() {
        // four worker threads, including this one.
        let pool = make_pool(4).unwrap();

        for _ in 0..100 {
            // empty job
            pool.submit(|_| {});
        }
    }

    #[test]
    fn child_jobs() {
        let pool = make_pool(4).unwrap();

        pool.submit(|worker| {
            for _ in 0..100 {
                // empty job
                worker.submit(|_| {});
            };
        }).wait().unwrap();
    }

    #[test]
    fn panic_in_the_jobqueue() {
        use std::any::Any;

        let pool = make_pool(4).unwrap();

        let mut handles = Vec::new();
        for i in 0..100 {
            // 4 threads, 20 panics.
            let handle = pool.submit(move |_| match i % 5 {
                0 => panic!(i),
                _ => {}
            });

            handles.push(handle);
        }

        for handle in handles {
            match handle.wait() {
                Ok(_) => {},
                Err(b) => {
                    let panic_val = b.downcast_ref::<i32>().unwrap();
                    assert_eq!(panic_val % 5, 0);
                }
            }
        }

    }

/*    #[test]
    fn scoping() {
        let pool = make_pool(4).unwrap();
        let this_worker = pool.get_worker();
        this_worker.submit(|worker| {
            let mut v = vec![0; 256];

            worker.scope(|scope| {
                for chunk in v.chunks_mut(32) {
                    scope.submit(move |_| {
                        for i in chunk { *i += 1 }
                    });
                }
            });

            for i in v {
                assert_eq!(i, 1);
            }
        }).wait();
    }*/
}<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private, convert, slice_patterns)]

extern crate rustc;
extern crate syntax;

use syntax::codemap::{Spanned, Span};
use syntax::parse::{PResult, token};
use syntax::ast::{TokenTree, TtDelimited, TtToken};
use syntax::{abi, ast};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ptr::P;
use syntax::owned_slice::OwnedSlice;
use syntax::util::small_vector::SmallVector;
use rustc::plugin::Registry;

fn tt_vec(tts: &[TokenTree]) -> Vec<TokenTree> {
    tts.iter().map(|tt| tt.clone()).collect()
}

fn build_string_from_idents(target: &mut String, tts: &[TokenTree]) -> Result<(), Span> {
    for t in tts {
        match t {
            &TtToken(_, token::Ident(ref i, _)) => {
                target.extend(i.as_str().chars());
            },
            &TtToken(_, token::Comma) => (),
            &TtDelimited(delim_span, ref delim) => {
                if delim.delim != token::DelimToken::Bracket {
                    return Err(delim_span);
                }
                try!(build_string_from_idents(target, &delim.tts[..]));
            }
            ref tt => return Err(tt.get_span()),
        }
    }
    Ok(())
}

fn fnconcat(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
            -> Box<MacResult + 'static> {
    if args.is_empty() {
        cx.span_err(sp, "fnconcat! can't be called with nothing");
        return DummyResult::any(sp);
    }
    let mut fn_tokens = tt_vec(args);
    fn_tokens[0] = if let &TtDelimited(delim_span, ref delim) = &fn_tokens[0] {
        if delim.delim != token::DelimToken::Bracket {
            cx.span_err(delim_span, "use square brackets (i.e. [..]) in place of the function name");
            return DummyResult::any(delim_span);
        }
        let mut concatenated = String::new();
        match build_string_from_idents(&mut concatenated, &delim.tts) {
            Ok(()) => (),
            Err(err_span) => {
                cx.span_err(err_span, "non-ident, non-comma token");
                return DummyResult::any(sp);
            },
        }
        if concatenated.is_empty() {
            cx.span_err(delim_span, "empty identifier");
            return DummyResult::any(sp);
        }
        TtToken(sp, token::Ident(cx.ident_of(concatenated.as_str()), token::Plain))
    } else {
        cx.span_err(sp, "use square brackets (i.e. [..]) in place of the function name");
        return DummyResult::any(sp);
    };
    fn_tokens.insert(0, TtToken(sp, token::Ident(cx.ident_of("fn"), token::Plain)));
    let mut p = cx.new_parser_from_tts(&fn_tokens[..]);
    if let Some(i) = p.parse_item() {
        return MacEager::items(SmallVector::one(i));
    }
    cx.span_err(sp, "couldn't parse a fn");
    return DummyResult::any(sp);
}

fn pull_tts_from_paren_groups(tts: &[TokenTree]) -> PResult<Vec<Vec<TokenTree>>> {
    let mut ret = Vec::new();
    for t in tts {
        match t {
            &TtDelimited(_, ref delim) if delim.delim == token::DelimToken::Paren => {
                ret.push(tt_vec(&delim.tts[..]));
            },
            _ => {

            },
        }
    }
    Ok(ret)
}

fn parse_pats_and_types(cx: &mut ExtCtxt, tts: Vec<TokenTree>) -> PResult<Vec<(P<ast::Pat>, P<ast::Ty>)>> {
    let mut ret = Vec::new();
    let mut parser = cx.new_parser_from_tts(&tts[..]);
    loop {
        let pat = try!(parser.parse_pat_nopanic());
        try!(parser.expect(&token::Colon));
        let ty = try!(parser.parse_ty_nopanic());
        ret.push((pat, ty));
        if !try!(parser.eat(&token::Comma)) {
            break;
        }
    }
    Ok(ret)
}

fn parse_exprs(cx: &mut ExtCtxt, tts: Vec<TokenTree>) -> PResult<Vec<P<ast::Expr>>> {
    let mut ret = Vec::new();
    let mut parser = cx.new_parser_from_tts(&tts[..]);
    loop {
        ret.push(try!(parser.parse_expr_nopanic()));
        if !try!(parser.eat(&token::Comma)) {
            break;
        }
    }
    Ok(ret)
}

fn try_mapping_parse_exprs(cx: &mut ExtCtxt, tts_vec: Vec<Vec<TokenTree>>) -> PResult<Vec<Vec<P<ast::Expr>>>> {
    let mut ret = Vec::new();
    for tts in tts_vec {
        ret.push(try!(parse_exprs(cx, tts)));
    }
    Ok(ret)
}

fn let_of_pat_type_and_expr(pat: P<ast::Pat>, ty: P<ast::Ty>, expr: P<ast::Expr>, span: Span) -> P<ast::Stmt> {
    let id = pat.id;
    let local = ast::Local {
        pat: pat,
        ty: Some(ty),
        init: Some(expr),
        id: id,
        span: span.clone(),
        source: ast::LocalLet,
    };
    let decl = ast::DeclLocal(P(local));
    let stmt = ast::StmtDecl(P(Spanned { node: decl, span: span.clone() }), id);
    P(Spanned { node: stmt, span: span })
}

fn unit_output(id: ast::NodeId, sp: Span) -> ast::FunctionRetTy {
    let ty = ast::Ty {
        id: id,
        node: ast::TyTup(Vec::new()),
        span: sp.clone(),
    };
    ast::Return(P(ty))
}

fn test_fn_item_of_ident_and_block(sp: Span, ident: ast::Ident, block: P<ast::Block>) -> P<ast::Item> {
    let id = block.id;
    let fn_decl = P(ast::FnDecl {
        inputs: Vec::new(),
        output: unit_output(id, sp),
        variadic: false,
    });
    let generics = ast::Generics {
        lifetimes: Vec::new(),
        ty_params: OwnedSlice::empty(),
        where_clause: ast::WhereClause {
            id: id,
            predicates: Vec::new(),
        },
    };
    let item_fn = ast::ItemFn(
        fn_decl,
        ast::Unsafety::Normal,
        ast::Constness::NotConst,
        abi::Rust,
        generics,
        block,
        );
    let test_attribute = ast::Attribute_ {
        id: ast::AttrId(0),
        style: ast::AttrOuter,
        value: P(Spanned { node: ast::MetaWord(token::InternedString::new("test")), span: sp.clone() }),
        is_sugared_doc: false,
    };
    P(ast::Item {
        ident: ident,
        attrs: vec![Spanned { node: test_attribute, span: sp.clone() }],
        id: id,
        node: item_fn,
        vis: ast::Public,
        span: sp,
    })
}

fn do_parametrization(cx: &mut ExtCtxt, sp: Span, base_name: ast::Ident,
                      params: &ast::Delimited, whole_block: TokenTree)
                      -> PResult<Box<MacResult + 'static>> {
    let mut items = Vec::new();
    let mut groups = try!(pull_tts_from_paren_groups(&params.tts[..]));
    let param_types = try!(parse_pats_and_types(cx, groups.remove(0)));
    let param_exprs_vec = try!(try_mapping_parse_exprs(cx, groups));
    let block = try!(cx.new_parser_from_tts(&vec![whole_block][..]).parse_block());
    for (e, exprs) in param_exprs_vec.into_iter().enumerate() {
        let mut new_stmts = Vec::new();
        for ((pat, ty), expr) in param_types.iter().cloned().zip(exprs.into_iter()) {
            new_stmts.push(let_of_pat_type_and_expr(pat, ty, expr, sp))
        }
        new_stmts.extend(block.stmts.iter().cloned());
        let param_block = P(ast::Block {
            stmts: new_stmts,
            .. (*block).clone()
        });
        let fn_name = format!("{}_{}", base_name.as_str(), e);
        let ident = cx.ident_of(fn_name.as_str());
        items.push(test_fn_item_of_ident_and_block(sp.clone(), ident, param_block));
    }
    Ok(MacEager::items(SmallVector::many(items)))
}

fn parametrize_test(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
                    -> Box<MacResult + 'static> {
    match args {
        [TtToken(_, token::Ident(ref name, _)),
         TtToken(_, token::Comma),
         TtDelimited(params_span, ref params),
         TtToken(_, token::Comma),
         TtDelimited(block_span, ref block)] => {
            if params.delim != token::DelimToken::Bracket {
                cx.span_err(params_span, "need square brackets around parameters");
                return DummyResult::any(params_span);
            }
            if block.delim != token::DelimToken::Brace {
                cx.span_err(block_span, "need curly braces around block");
                return DummyResult::any(block_span);
            }
            if params.tts.len() < 2 {
                cx.span_err(params_span, "need at least param types and one param");
                return DummyResult::any(params_span);
            }
            match do_parametrization(cx, sp, name.clone(), params, TtDelimited(block_span, block.clone())) {
                Ok(r) => return r,
                Err(_) => {
                    cx.span_err(sp, "error while parsing");
                    return DummyResult::any(sp);
                }
            }
        },
        _ => {
            cx.span_err(sp, "badly-structured parametrize_test!");
            return DummyResult::any(sp);
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fnconcat", fnconcat);
    reg.register_macro("parametrize_test", parametrize_test);
}
<commit_msg>Use the FromIterator impl that uses Result.<commit_after>#![feature(plugin_registrar, rustc_private, convert, slice_patterns)]

extern crate rustc;
extern crate syntax;

use syntax::codemap::{Spanned, Span};
use syntax::parse::{PResult, token};
use syntax::ast::{TokenTree, TtDelimited, TtToken};
use syntax::{abi, ast};
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ptr::P;
use syntax::owned_slice::OwnedSlice;
use syntax::util::small_vector::SmallVector;
use rustc::plugin::Registry;

fn tt_vec(tts: &[TokenTree]) -> Vec<TokenTree> {
    tts.iter().map(|tt| tt.clone()).collect()
}

fn build_string_from_idents(target: &mut String, tts: &[TokenTree]) -> Result<(), Span> {
    for t in tts {
        match t {
            &TtToken(_, token::Ident(ref i, _)) => {
                target.extend(i.as_str().chars());
            },
            &TtToken(_, token::Comma) => (),
            &TtDelimited(delim_span, ref delim) => {
                if delim.delim != token::DelimToken::Bracket {
                    return Err(delim_span);
                }
                try!(build_string_from_idents(target, &delim.tts[..]));
            }
            ref tt => return Err(tt.get_span()),
        }
    }
    Ok(())
}

fn fnconcat(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
            -> Box<MacResult + 'static> {
    if args.is_empty() {
        cx.span_err(sp, "fnconcat! can't be called with nothing");
        return DummyResult::any(sp);
    }
    let mut fn_tokens = tt_vec(args);
    fn_tokens[0] = if let &TtDelimited(delim_span, ref delim) = &fn_tokens[0] {
        if delim.delim != token::DelimToken::Bracket {
            cx.span_err(delim_span, "use square brackets (i.e. [..]) in place of the function name");
            return DummyResult::any(delim_span);
        }
        let mut concatenated = String::new();
        match build_string_from_idents(&mut concatenated, &delim.tts) {
            Ok(()) => (),
            Err(err_span) => {
                cx.span_err(err_span, "non-ident, non-comma token");
                return DummyResult::any(sp);
            },
        }
        if concatenated.is_empty() {
            cx.span_err(delim_span, "empty identifier");
            return DummyResult::any(sp);
        }
        TtToken(sp, token::Ident(cx.ident_of(concatenated.as_str()), token::Plain))
    } else {
        cx.span_err(sp, "use square brackets (i.e. [..]) in place of the function name");
        return DummyResult::any(sp);
    };
    fn_tokens.insert(0, TtToken(sp, token::Ident(cx.ident_of("fn"), token::Plain)));
    let mut p = cx.new_parser_from_tts(&fn_tokens[..]);
    if let Some(i) = p.parse_item() {
        return MacEager::items(SmallVector::one(i));
    }
    cx.span_err(sp, "couldn't parse a fn");
    return DummyResult::any(sp);
}

fn pull_tts_from_paren_groups(tts: &[TokenTree]) -> PResult<Vec<Vec<TokenTree>>> {
    let mut ret = Vec::new();
    for t in tts {
        match t {
            &TtDelimited(_, ref delim) if delim.delim == token::DelimToken::Paren => {
                ret.push(tt_vec(&delim.tts[..]));
            },
            _ => {

            },
        }
    }
    Ok(ret)
}

fn parse_pats_and_types(cx: &mut ExtCtxt, tts: Vec<TokenTree>) -> PResult<Vec<(P<ast::Pat>, P<ast::Ty>)>> {
    let mut ret = Vec::new();
    let mut parser = cx.new_parser_from_tts(&tts[..]);
    loop {
        let pat = try!(parser.parse_pat_nopanic());
        try!(parser.expect(&token::Colon));
        let ty = try!(parser.parse_ty_nopanic());
        ret.push((pat, ty));
        if !try!(parser.eat(&token::Comma)) {
            break;
        }
    }
    Ok(ret)
}

fn parse_exprs(cx: &mut ExtCtxt, tts: Vec<TokenTree>) -> PResult<Vec<P<ast::Expr>>> {
    let mut ret = Vec::new();
    let mut parser = cx.new_parser_from_tts(&tts[..]);
    loop {
        ret.push(try!(parser.parse_expr_nopanic()));
        if !try!(parser.eat(&token::Comma)) {
            break;
        }
    }
    Ok(ret)
}

fn let_of_pat_type_and_expr(pat: P<ast::Pat>, ty: P<ast::Ty>, expr: P<ast::Expr>, span: Span) -> P<ast::Stmt> {
    let id = pat.id;
    let local = ast::Local {
        pat: pat,
        ty: Some(ty),
        init: Some(expr),
        id: id,
        span: span.clone(),
        source: ast::LocalLet,
    };
    let decl = ast::DeclLocal(P(local));
    let stmt = ast::StmtDecl(P(Spanned { node: decl, span: span.clone() }), id);
    P(Spanned { node: stmt, span: span })
}

fn unit_output(id: ast::NodeId, sp: Span) -> ast::FunctionRetTy {
    let ty = ast::Ty {
        id: id,
        node: ast::TyTup(Vec::new()),
        span: sp.clone(),
    };
    ast::Return(P(ty))
}

fn test_fn_item_of_ident_and_block(sp: Span, ident: ast::Ident, block: P<ast::Block>) -> P<ast::Item> {
    let id = block.id;
    let fn_decl = P(ast::FnDecl {
        inputs: Vec::new(),
        output: unit_output(id, sp),
        variadic: false,
    });
    let generics = ast::Generics {
        lifetimes: Vec::new(),
        ty_params: OwnedSlice::empty(),
        where_clause: ast::WhereClause {
            id: id,
            predicates: Vec::new(),
        },
    };
    let item_fn = ast::ItemFn(
        fn_decl,
        ast::Unsafety::Normal,
        ast::Constness::NotConst,
        abi::Rust,
        generics,
        block,
        );
    let test_attribute = ast::Attribute_ {
        id: ast::AttrId(0),
        style: ast::AttrOuter,
        value: P(Spanned { node: ast::MetaWord(token::InternedString::new("test")), span: sp.clone() }),
        is_sugared_doc: false,
    };
    P(ast::Item {
        ident: ident,
        attrs: vec![Spanned { node: test_attribute, span: sp.clone() }],
        id: id,
        node: item_fn,
        vis: ast::Public,
        span: sp,
    })
}

fn do_parametrization(cx: &mut ExtCtxt, sp: Span, base_name: ast::Ident,
                      params: &ast::Delimited, whole_block: TokenTree)
                      -> PResult<Box<MacResult + 'static>> {
    let mut items = Vec::new();
    let mut groups = try!(pull_tts_from_paren_groups(&params.tts[..]));
    let param_types = try!(parse_pats_and_types(cx, groups.remove(0)));
    let param_exprs_vec: Vec<Vec<P<ast::Expr>>> = try!(groups.into_iter().map(|tts| parse_exprs(cx, tts)).collect());
    let block = try!(cx.new_parser_from_tts(&vec![whole_block][..]).parse_block());
    for (e, exprs) in param_exprs_vec.into_iter().enumerate() {
        let mut new_stmts = Vec::new();
        for ((pat, ty), expr) in param_types.iter().cloned().zip(exprs.into_iter()) {
            new_stmts.push(let_of_pat_type_and_expr(pat, ty, expr, sp))
        }
        new_stmts.extend(block.stmts.iter().cloned());
        let param_block = P(ast::Block {
            stmts: new_stmts,
            .. (*block).clone()
        });
        let fn_name = format!("{}_{}", base_name.as_str(), e);
        let ident = cx.ident_of(fn_name.as_str());
        items.push(test_fn_item_of_ident_and_block(sp.clone(), ident, param_block));
    }
    Ok(MacEager::items(SmallVector::many(items)))
}

fn parametrize_test(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
                    -> Box<MacResult + 'static> {
    match args {
        [TtToken(_, token::Ident(ref name, _)),
         TtToken(_, token::Comma),
         TtDelimited(params_span, ref params),
         TtToken(_, token::Comma),
         TtDelimited(block_span, ref block)] => {
            if params.delim != token::DelimToken::Bracket {
                cx.span_err(params_span, "need square brackets around parameters");
                return DummyResult::any(params_span);
            }
            if block.delim != token::DelimToken::Brace {
                cx.span_err(block_span, "need curly braces around block");
                return DummyResult::any(block_span);
            }
            if params.tts.len() < 2 {
                cx.span_err(params_span, "need at least param types and one param");
                return DummyResult::any(params_span);
            }
            match do_parametrization(cx, sp, name.clone(), params, TtDelimited(block_span, block.clone())) {
                Ok(r) => return r,
                Err(_) => {
                    cx.span_err(sp, "error while parsing");
                    return DummyResult::any(sp);
                }
            }
        },
        _ => {
            cx.span_err(sp, "badly-structured parametrize_test!");
            return DummyResult::any(sp);
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("fnconcat", fnconcat);
    reg.register_macro("parametrize_test", parametrize_test);
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::fs::{self, read_dir};

pub struct DeepWalk {
    root: PathBuf,
}

impl DeepWalk {
    pub fn new<P: AsRef<Path>>(root: P) -> Self {
        DeepWalk { root: root.as_ref().to_path_buf() }
    }
}

impl IntoIterator for DeepWalk {
    type Item = Result<Entry, Error>;
    type IntoIter = Iter;

    fn into_iter(self) -> Iter {
        Iter { root: self.root }
    }
}

pub struct Iter {
    root: PathBuf,
}

// TODO: Remove and implement Iterator for DeepWalk.
impl Iterator for Iter {
    type Item = Result<Entry, Error>;

    fn next(&mut self) -> Option<Result<Entry, Error>> {
        let metadata = fs::metadata(&self.root);
        None
    }
}

pub struct Entry {
    //
}

pub struct Error {
    //
}

#[cfg(test)]
mod tests {
    use super::DeepWalk;
    use std::path::Path;

    fn get_test_roots() -> &'static[&'static str] {
        const DATA: &'static[&'static str] = &["", "a", "test", "eee/aaa", "some/long/path"];
        DATA
    }

    #[test]
    fn deep_walk_new() {
        for val in get_test_roots() {
            assert_eq!(DeepWalk::new(val).root, Path::new(val));
        }
    }

    #[test]
    fn deep_walk_into_iterator() {
        for val in get_test_roots() {
            assert_eq!(DeepWalk::new(val).into_iter().root, Path::new(val));
        }
    }
}
<commit_msg>Work in progress<commit_after>use std::path::{Path, PathBuf};
use std::fs::{self, ReadDir, DirEntry};
use std::io::Error;

pub struct DeepWalk {
    root: PathBuf,
}

impl DeepWalk {
    pub fn new<P: AsRef<Path>>(root: P) -> Self {
        DeepWalk { root: root.as_ref().to_path_buf() }
    }
}

impl IntoIterator for DeepWalk {
    type Item = Result<DirEntry, Error>;
    type IntoIter = Iter;

    fn into_iter(self) -> Iter {
        Iter { root: Some(self.root), dirs: Vec::new() }
    }
}

pub struct Iter {
    root: Option<PathBuf>,
    dirs: Vec<ReadDir>,
}

// TODO: Remove and implement Iterator for DeepWalk.
impl Iterator for Iter {
    type Item = Result<DirEntry, Error>;

    fn next(&mut self) -> Option<Result<DirEntry, Error>> {
        if let Some(path) = self.root.take() {
            match fs::read_dir(path) {
                Ok(dir) => self.dirs.push(dir),
                Err(err) => return Some(Err(err)),
            }
        }

        while !self.dirs.is_empty() {
            // TODO: FIXME.
            break;
        }

        None
    }
}

#[cfg(test)]
mod tests {
    use super::DeepWalk;
    use std::path::{Path, PathBuf};

    fn get_test_roots() -> &'static[&'static str] {
        const DATA: &'static[&'static str] = &["", "a", "test", "eee/aaa", "some/long/path"];
        DATA
    }

    #[test]
    fn deep_walk_new() {
        for val in get_test_roots() {
            assert_eq!(DeepWalk::new(val).root, Path::new(val));
        }
    }

    #[test]
    fn deep_walk_into_iterator() {
        for val in get_test_roots() {
            assert_eq!(DeepWalk::new(val).into_iter().root, Some(PathBuf::from(val)));
        }
    }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate url;
extern crate serde_json;

use std::result;
use std::io;
use std::io::Read;

use hyper::{Client, Url};
use hyper::header::UserAgent;

const LANGUAGE_URL_MARKER:&'static str = "{language}";

#[derive(Debug)]
pub enum Error {
    UrlError(url::ParseError),
    HyperError(hyper::error::Error),
    HTTPError(hyper::client::response::Response),
    IOError(io::Error),
    JSONError(serde_json::error::Error),
    JSONPathError,
    InvalidParameter(String),
}

impl std::convert::From<url::ParseError> for Error {
    fn from(e: url::ParseError) -> Self {
        Error::UrlError(e)
    }
}

impl std::convert::From<hyper::error::Error> for Error {
    fn from(e: hyper::error::Error) -> Self {
        Error::HyperError(e)
    }
}

impl std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::IOError(e)
    }
}

impl std::convert::From<serde_json::error::Error> for Error {
    fn from(e: serde_json::error::Error) -> Self {
        Error::JSONError(e)
    }
}

pub type Result<T> = result::Result<T, Error>;

pub struct Wikipedia {
    pub pre_language_url:String,
    pub post_language_url:String,
    pub user_agent:String,
    pub language:String,
    pub search_results:u32,
}

impl Default for Wikipedia {
    fn default() -> Self {
        Wikipedia {
            pre_language_url: "https://".to_owned(),
            post_language_url: ".wikipedia.org/w/api.php".to_owned(),
            user_agent: "wikipedia (https://github.com/seppo0010/wikipedia-rs)".to_owned(),
            language: "en".to_owned(),
            search_results: 10,
        }
    }
}

impl Wikipedia {
    pub fn base_url(&self) -> String {
        format!("{}{}{}", self.pre_language_url, self.language, self.post_language_url)
    }

    pub fn set_base_url(&mut self, base_url: &str) {
        let index = match base_url.find(LANGUAGE_URL_MARKER) {
            Some(i) => i,
            None => {
                self.pre_language_url = base_url.to_owned();
                self.language = "".to_owned();
                self.post_language_url = "".to_owned();
                return;
            }
        };
        self.pre_language_url = base_url[0..index].to_owned();
        self.post_language_url = base_url[index+LANGUAGE_URL_MARKER.len()..].to_owned();
    }

    fn query(&self, url: Url) -> Result<serde_json::Value> {
        let client = Client::new();
        let mut response = try!(client.get(url)
            .header(UserAgent(self.user_agent.clone()))
            .send());

        if !response.status.is_success() {
            return Err(Error::HTTPError(response));
        }

        let mut response_str = String::new();
        try!(response.read_to_string(&mut response_str));

        Ok(try!(serde_json::from_str(&*response_str)))
    }

    fn search_url(&self, query: &str) -> Result<Url> {
        let mut url = try!(Url::parse(&*self.base_url()));
        let results = &*format!("{}", self.search_results);
        url.set_query_from_pairs(vec![
                ("list", "search"),
                ("srprop", ""),
                ("srlimit", results),
                ("srsearch", query),
                ("continue", ""),
                ("format", "json"),
                ("action", "query"),
                ].into_iter());
        Ok(url)
    }

    pub fn search(&self, query: &str) -> Result<Vec<String>> {
        let url = try!(self.search_url(query));
        let data = try!(self.query(url));

        // There has to be a better way to write the following code
        Ok(try!(
            data.as_object()
            .and_then(|x| x.get("query"))
            .and_then(|x| x.as_object())
            .and_then(|x| x.get("search"))
            .and_then(|x| x.as_array())
            .ok_or(Error::JSONPathError)
            ).into_iter().filter_map(|i|
                i.as_object()
                .and_then(|i| i.get("title"))
                .and_then(|s| s.as_string().map(|s| s.to_owned()))
                ).collect())
    }

    fn geosearch_url(&self, latitude: f64, longitude: f64, radius: u16) -> Result<Url> {
        if latitude < -90.0 || latitude > 90.0 {
            return Err(Error::InvalidParameter("latitude".to_string()))
        }
        if longitude < -180.0 || longitude > 180.0 {
            return Err(Error::InvalidParameter("longitude".to_string()))
        }
        if radius < 10 || radius > 10000 {
            return Err(Error::InvalidParameter("radius".to_string()))
        }
        let mut url = try!(Url::parse(&*self.base_url()));
        let results = &*format!("{}", self.search_results);
        url.set_query_from_pairs(vec![
                ("list", "geosearch"),
                ("gsradius", &*format!("{}", radius)),
                ("gscoord", &*format!("{}|{}", latitude, longitude)),
                ("gslimit", results),
                ("format", "json"),
                ("action", "query"),
                ].into_iter());
        Ok(url)
    }

    pub fn geosearch(&self, latitude: f64, longitude: f64, radius: u16) -> Result<Vec<String>> {
        let url = try!(self.geosearch_url(latitude, longitude, radius));
        let data = try!(self.query(url));

        // There has to be a better way to write the following code
        Ok(try!(
            data.as_object()
            .and_then(|x| x.get("query"))
            .and_then(|x| x.as_object())
            .and_then(|x| x.get("geosearch"))
            .and_then(|x| x.as_array())
            .ok_or(Error::JSONPathError)
            ).into_iter().filter_map(|i|
                i.as_object()
                .and_then(|i| i.get("title"))
                .and_then(|s| s.as_string().map(|s| s.to_owned()))
                ).collect())
    }
}

#[test]
fn base_url() {
    let mut wikipedia = Wikipedia::default();
    assert_eq!(wikipedia.base_url(), "https://en.wikipedia.org/w/api.php");
    wikipedia.language = "es".to_owned();
    assert_eq!(wikipedia.base_url(), "https://es.wikipedia.org/w/api.php");

    wikipedia.set_base_url("https://hello.{language}.world/");
    assert_eq!(wikipedia.base_url(), "https://hello.es.world/");

    wikipedia.set_base_url("https://hello.world/");
    assert_eq!(wikipedia.base_url(), "https://hello.world/");
}

#[test]
fn search_url() {
    let wikipedia = Wikipedia::default();
    assert_eq!(&*format!("{}", wikipedia.search_url("hello world").unwrap()),
            "https://en.wikipedia.org/w/api.php?list=search&srprop=&srlimit=10&srsearch=hello+world&continue=&format=json&action=query");
}

#[test]
fn search() {
    let wikipedia = Wikipedia::default();
    let results = wikipedia.search("hello world").unwrap();
    assert!(results.len() > 0);
    assert!(results.contains(&"\"Hello, World!\" program".to_owned()));
}

#[test]
fn geosearch_url() {
    let wikipedia = Wikipedia::default();
    assert_eq!(&*format!("{}", wikipedia.geosearch_url(-34.603333, -58.381667, 10).unwrap()),
            "https://en.wikipedia.org/w/api.php?list=geosearch&gsradius=10&gscoord=-34.603333%7C-58.381667&gslimit=10&format=json&action=query");
}

#[test]
fn geosearch() {
    let wikipedia = Wikipedia::default();
    let results = wikipedia.geosearch(-34.603333, -58.381667, 10).unwrap();
    assert!(results.len() > 0);
    assert!(results.contains(&"Buenos Aires".to_owned()));
}
<commit_msg>Extract result parsing code<commit_after>extern crate hyper;
extern crate url;
extern crate serde_json;

use std::result;
use std::io;
use std::io::Read;

use hyper::{Client, Url};
use hyper::header::UserAgent;

const LANGUAGE_URL_MARKER:&'static str = "{language}";

macro_rules! results {
    ($data: expr, $query_field: expr) => {
        // There has to be a better way to write the following code
        Ok(try!(
            $data.as_object()
            .and_then(|x| x.get("query"))
            .and_then(|x| x.as_object())
            .and_then(|x| x.get($query_field))
            .and_then(|x| x.as_array())
            .ok_or(Error::JSONPathError)
            ).into_iter().filter_map(|i|
                i.as_object()
                .and_then(|i| i.get("title"))
                .and_then(|s| s.as_string().map(|s| s.to_owned()))
                ).collect())
    }
}

#[derive(Debug)]
pub enum Error {
    UrlError(url::ParseError),
    HyperError(hyper::error::Error),
    HTTPError(hyper::client::response::Response),
    IOError(io::Error),
    JSONError(serde_json::error::Error),
    JSONPathError,
    InvalidParameter(String),
}

impl std::convert::From<url::ParseError> for Error {
    fn from(e: url::ParseError) -> Self {
        Error::UrlError(e)
    }
}

impl std::convert::From<hyper::error::Error> for Error {
    fn from(e: hyper::error::Error) -> Self {
        Error::HyperError(e)
    }
}

impl std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::IOError(e)
    }
}

impl std::convert::From<serde_json::error::Error> for Error {
    fn from(e: serde_json::error::Error) -> Self {
        Error::JSONError(e)
    }
}

pub type Result<T> = result::Result<T, Error>;

pub struct Wikipedia {
    pub pre_language_url:String,
    pub post_language_url:String,
    pub user_agent:String,
    pub language:String,
    pub search_results:u32,
}

impl Default for Wikipedia {
    fn default() -> Self {
        Wikipedia {
            pre_language_url: "https://".to_owned(),
            post_language_url: ".wikipedia.org/w/api.php".to_owned(),
            user_agent: "wikipedia (https://github.com/seppo0010/wikipedia-rs)".to_owned(),
            language: "en".to_owned(),
            search_results: 10,
        }
    }
}

impl Wikipedia {
    pub fn base_url(&self) -> String {
        format!("{}{}{}", self.pre_language_url, self.language, self.post_language_url)
    }

    pub fn set_base_url(&mut self, base_url: &str) {
        let index = match base_url.find(LANGUAGE_URL_MARKER) {
            Some(i) => i,
            None => {
                self.pre_language_url = base_url.to_owned();
                self.language = "".to_owned();
                self.post_language_url = "".to_owned();
                return;
            }
        };
        self.pre_language_url = base_url[0..index].to_owned();
        self.post_language_url = base_url[index+LANGUAGE_URL_MARKER.len()..].to_owned();
    }

    fn query(&self, url: Url) -> Result<serde_json::Value> {
        let client = Client::new();
        let mut response = try!(client.get(url)
            .header(UserAgent(self.user_agent.clone()))
            .send());

        if !response.status.is_success() {
            return Err(Error::HTTPError(response));
        }

        let mut response_str = String::new();
        try!(response.read_to_string(&mut response_str));

        Ok(try!(serde_json::from_str(&*response_str)))
    }

    fn search_url(&self, query: &str) -> Result<Url> {
        let mut url = try!(Url::parse(&*self.base_url()));
        let results = &*format!("{}", self.search_results);
        url.set_query_from_pairs(vec![
                ("list", "search"),
                ("srprop", ""),
                ("srlimit", results),
                ("srsearch", query),
                ("continue", ""),
                ("format", "json"),
                ("action", "query"),
                ].into_iter());
        Ok(url)
    }

    pub fn search(&self, query: &str) -> Result<Vec<String>> {
        let url = try!(self.search_url(query));
        let data = try!(self.query(url));

        results!(data, "search")
    }

    fn geosearch_url(&self, latitude: f64, longitude: f64, radius: u16) -> Result<Url> {
        if latitude < -90.0 || latitude > 90.0 {
            return Err(Error::InvalidParameter("latitude".to_string()))
        }
        if longitude < -180.0 || longitude > 180.0 {
            return Err(Error::InvalidParameter("longitude".to_string()))
        }
        if radius < 10 || radius > 10000 {
            return Err(Error::InvalidParameter("radius".to_string()))
        }
        let mut url = try!(Url::parse(&*self.base_url()));
        let results = &*format!("{}", self.search_results);
        url.set_query_from_pairs(vec![
                ("list", "geosearch"),
                ("gsradius", &*format!("{}", radius)),
                ("gscoord", &*format!("{}|{}", latitude, longitude)),
                ("gslimit", results),
                ("format", "json"),
                ("action", "query"),
                ].into_iter());
        Ok(url)
    }

    pub fn geosearch(&self, latitude: f64, longitude: f64, radius: u16) -> Result<Vec<String>> {
        let url = try!(self.geosearch_url(latitude, longitude, radius));
        let data = try!(self.query(url));

        results!(data, "geosearch")
    }
}

#[test]
fn base_url() {
    let mut wikipedia = Wikipedia::default();
    assert_eq!(wikipedia.base_url(), "https://en.wikipedia.org/w/api.php");
    wikipedia.language = "es".to_owned();
    assert_eq!(wikipedia.base_url(), "https://es.wikipedia.org/w/api.php");

    wikipedia.set_base_url("https://hello.{language}.world/");
    assert_eq!(wikipedia.base_url(), "https://hello.es.world/");

    wikipedia.set_base_url("https://hello.world/");
    assert_eq!(wikipedia.base_url(), "https://hello.world/");
}

#[test]
fn search_url() {
    let wikipedia = Wikipedia::default();
    assert_eq!(&*format!("{}", wikipedia.search_url("hello world").unwrap()),
            "https://en.wikipedia.org/w/api.php?list=search&srprop=&srlimit=10&srsearch=hello+world&continue=&format=json&action=query");
}

#[test]
fn search() {
    let wikipedia = Wikipedia::default();
    let results = wikipedia.search("hello world").unwrap();
    assert!(results.len() > 0);
    assert!(results.contains(&"\"Hello, World!\" program".to_owned()));
}

#[test]
fn geosearch_url() {
    let wikipedia = Wikipedia::default();
    assert_eq!(&*format!("{}", wikipedia.geosearch_url(-34.603333, -58.381667, 10).unwrap()),
            "https://en.wikipedia.org/w/api.php?list=geosearch&gsradius=10&gscoord=-34.603333%7C-58.381667&gslimit=10&format=json&action=query");
}

#[test]
fn geosearch() {
    let wikipedia = Wikipedia::default();
    let results = wikipedia.geosearch(-34.603333, -58.381667, 10).unwrap();
    assert!(results.len() > 0);
    assert!(results.contains(&"Buenos Aires".to_owned()));
}
<|endoftext|>


<commit_before>//! Modbus implementation in pure Rust.
//!
//! # Examples
//!
//! ```
//! # extern crate modbus;
//! # extern crate test_server;
//! # use test_server::start_dummy_server;
//! # fn main() {
//! use modbus::{Client, Coil};
//! use modbus::tcp;
//! # if cfg!(feature = "modbus-server-tests") {
//! # let (_s, port) = start_dummy_server(Some(22221));
//!
//! let mut cfg = tcp::Config::default();
//! # cfg.tcp_port = port;
//! let mut client = tcp::Transport::new_with_cfg("127.0.0.1", cfg).unwrap();
//! assert!(client.write_single_coil(0, Coil::On).is_ok());
//! # }
//! # }
//! ```

#[macro_use]
extern crate enum_primitive;
extern crate byteorder;

use std::fmt;
use std::io;
use std::str::FromStr;

pub mod binary;
mod client;

pub mod scoped;

/// The Modbus TCP backend implements a Modbus variant used for communication over TCP/IPv4 networks.
pub mod tcp;
pub use client::Client;
pub use tcp::Config;
pub use tcp::Transport;

type Address = u16;
type Quantity = u16;
type Value = u16;

enum Function<'a> {
    ReadCoils(Address, Quantity),
    ReadDiscreteInputs(Address, Quantity),
    ReadHoldingRegisters(Address, Quantity),
    ReadInputRegisters(Address, Quantity),
    WriteSingleCoil(Address, Value),
    WriteSingleRegister(Address, Value),
    WriteMultipleCoils(Address, Quantity, &'a [u8]),
    WriteMultipleRegisters(Address, Quantity, &'a [u8]),
}

impl<'a> Function<'a> {
    fn code(&self) -> u8 {
        match *self {
            Function::ReadCoils(_, _) => 0x01,
            Function::ReadDiscreteInputs(_, _) => 0x02,
            Function::ReadHoldingRegisters(_, _) => 0x03,
            Function::ReadInputRegisters(_, _) => 0x04,
            Function::WriteSingleCoil(_, _) => 0x05,
            Function::WriteSingleRegister(_, _) => 0x06,
            Function::WriteMultipleCoils(_, _, _) => 0x0f,
            Function::WriteMultipleRegisters(_, _, _) => 0x10,
        }
        // ReadExceptionStatus     = 0x07,
        // ReportSlaveId           = 0x11,
        // MaskWriteRegister       = 0x16,
        // WriteAndReadRegisters   = 0x17
    }
}

enum_from_primitive! {
#[derive(Debug, PartialEq)]
/// Modbus exception codes returned from the server.
pub enum ExceptionCode {
    IllegalFunction         = 0x01,
    IllegalDataAddress      = 0x02,
    IllegalDataValue        = 0x03,
    SlaveOrServerFailure    = 0x04,
    Acknowledge             = 0x05,
    SlaveOrServerBusy       = 0x06,
    NegativeAcknowledge     = 0x07,
    MemoryParity            = 0x08,
    NotDefined              = 0x09,
    GatewayPath             = 0x0a,
    GatewayTarget           = 0x0b
}
}

/// `InvalidData` reasons
#[derive(Debug)]
pub enum Reason {
    UnexpectedReplySize,
    BytecountNotEven,
    SendBufferEmpty,
    RecvBufferEmpty,
    SendBufferTooBig,
    DecodingError,
    EncodingError,
    InvalidByteorder,
    Custom(String),
}

/// Combination of Modbus, IO and data corruption errors
#[derive(Debug)]
pub enum Error {
    Exception(ExceptionCode),
    Io(io::Error),
    InvalidResponse,
    InvalidData(Reason),
    InvalidFunction,
    ParseCoilError,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Error::*;

        match *self {
            Exception(ref code) => write!(f, "modbus exception: {:?}", code),
            Io(ref err) => write!(f, "I/O error: {}", err),
            InvalidResponse => write!(f, "invalid response"),
            InvalidData(ref reason) => write!(f, "invalid data: {:?}", reason),
            InvalidFunction => write!(f, "invalid modbus function"),
            ParseCoilError => write!(f, "parse coil could not be parsed"),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use Error::*;

        match *self {
            Exception(_) => "modbus exception",
            Io(_) => "I/O error",
            InvalidResponse => "invalid response",
            InvalidData(_) => "invalid data",
            InvalidFunction => "invalid modbus function",
            ParseCoilError => "parse coil could not be parsed",
        }
    }

    fn cause(&self) -> Option<&dyn std::error::Error> {
        match *self {
            Error::Io(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<ExceptionCode> for Error {
    fn from(err: ExceptionCode) -> Error {
        Error::Exception(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

/// Result type used to nofify success or failure in communication
pub type Result<T> = std::result::Result<T, Error>;

/// Single bit status values, used in read or write coil functions
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Coil {
    On,
    Off,
}

impl Coil {
    fn code(self) -> u16 {
        match self {
            Coil::On => 0xff00,
            Coil::Off => 0x0000,
        }
    }
}

impl FromStr for Coil {
    type Err = Error;
    fn from_str(s: &str) -> Result<Coil> {
        if s == "On" {
            Ok(Coil::On)
        } else if s == "Off" {
            Ok(Coil::Off)
        } else {
            Err(Error::ParseCoilError)
        }
    }
}
<commit_msg>added implementations of From<bool> and Not for Coil<commit_after>//! Modbus implementation in pure Rust.
//!
//! # Examples
//!
//! ```
//! # extern crate modbus;
//! # extern crate test_server;
//! # use test_server::start_dummy_server;
//! # fn main() {
//! use modbus::{Client, Coil};
//! use modbus::tcp;
//! # if cfg!(feature = "modbus-server-tests") {
//! # let (_s, port) = start_dummy_server(Some(22221));
//!
//! let mut cfg = tcp::Config::default();
//! # cfg.tcp_port = port;
//! let mut client = tcp::Transport::new_with_cfg("127.0.0.1", cfg).unwrap();
//! assert!(client.write_single_coil(0, Coil::On).is_ok());
//! # }
//! # }
//! ```

#[macro_use]
extern crate enum_primitive;
extern crate byteorder;

use std::fmt;
use std::io;
use std::str::FromStr;

pub mod binary;
mod client;

pub mod scoped;

/// The Modbus TCP backend implements a Modbus variant used for communication over TCP/IPv4 networks.
pub mod tcp;
pub use client::Client;
pub use tcp::Config;
pub use tcp::Transport;

type Address = u16;
type Quantity = u16;
type Value = u16;

enum Function<'a> {
    ReadCoils(Address, Quantity),
    ReadDiscreteInputs(Address, Quantity),
    ReadHoldingRegisters(Address, Quantity),
    ReadInputRegisters(Address, Quantity),
    WriteSingleCoil(Address, Value),
    WriteSingleRegister(Address, Value),
    WriteMultipleCoils(Address, Quantity, &'a [u8]),
    WriteMultipleRegisters(Address, Quantity, &'a [u8]),
}

impl<'a> Function<'a> {
    fn code(&self) -> u8 {
        match *self {
            Function::ReadCoils(_, _) => 0x01,
            Function::ReadDiscreteInputs(_, _) => 0x02,
            Function::ReadHoldingRegisters(_, _) => 0x03,
            Function::ReadInputRegisters(_, _) => 0x04,
            Function::WriteSingleCoil(_, _) => 0x05,
            Function::WriteSingleRegister(_, _) => 0x06,
            Function::WriteMultipleCoils(_, _, _) => 0x0f,
            Function::WriteMultipleRegisters(_, _, _) => 0x10,
        }
        // ReadExceptionStatus     = 0x07,
        // ReportSlaveId           = 0x11,
        // MaskWriteRegister       = 0x16,
        // WriteAndReadRegisters   = 0x17
    }
}

enum_from_primitive! {
#[derive(Debug, PartialEq)]
/// Modbus exception codes returned from the server.
pub enum ExceptionCode {
    IllegalFunction         = 0x01,
    IllegalDataAddress      = 0x02,
    IllegalDataValue        = 0x03,
    SlaveOrServerFailure    = 0x04,
    Acknowledge             = 0x05,
    SlaveOrServerBusy       = 0x06,
    NegativeAcknowledge     = 0x07,
    MemoryParity            = 0x08,
    NotDefined              = 0x09,
    GatewayPath             = 0x0a,
    GatewayTarget           = 0x0b
}
}

/// `InvalidData` reasons
#[derive(Debug)]
pub enum Reason {
    UnexpectedReplySize,
    BytecountNotEven,
    SendBufferEmpty,
    RecvBufferEmpty,
    SendBufferTooBig,
    DecodingError,
    EncodingError,
    InvalidByteorder,
    Custom(String),
}

/// Combination of Modbus, IO and data corruption errors
#[derive(Debug)]
pub enum Error {
    Exception(ExceptionCode),
    Io(io::Error),
    InvalidResponse,
    InvalidData(Reason),
    InvalidFunction,
    ParseCoilError,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Error::*;

        match *self {
            Exception(ref code) => write!(f, "modbus exception: {:?}", code),
            Io(ref err) => write!(f, "I/O error: {}", err),
            InvalidResponse => write!(f, "invalid response"),
            InvalidData(ref reason) => write!(f, "invalid data: {:?}", reason),
            InvalidFunction => write!(f, "invalid modbus function"),
            ParseCoilError => write!(f, "parse coil could not be parsed"),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        use Error::*;

        match *self {
            Exception(_) => "modbus exception",
            Io(_) => "I/O error",
            InvalidResponse => "invalid response",
            InvalidData(_) => "invalid data",
            InvalidFunction => "invalid modbus function",
            ParseCoilError => "parse coil could not be parsed",
        }
    }

    fn cause(&self) -> Option<&dyn std::error::Error> {
        match *self {
            Error::Io(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<ExceptionCode> for Error {
    fn from(err: ExceptionCode) -> Error {
        Error::Exception(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

/// Result type used to nofify success or failure in communication
pub type Result<T> = std::result::Result<T, Error>;

/// Single bit status values, used in read or write coil functions
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Coil {
    On,
    Off,
}

impl Coil {
    fn code(self) -> u16 {
        match self {
            Coil::On => 0xff00,
            Coil::Off => 0x0000,
        }
    }
}

impl FromStr for Coil {
    type Err = Error;
    fn from_str(s: &str) -> Result<Coil> {
        if s == "On" {
            Ok(Coil::On)
        } else if s == "Off" {
            Ok(Coil::Off)
        } else {
            Err(Error::ParseCoilError)
        }
    }
}

impl From<bool> for Coil {
    fn from(b: bool) -> Coil {
        if b {
            Coil::On
        } else {
            Coil::Off
        }
    }
}

impl std::ops::Not for Coil {
    type Output = Coil;

    fn not(self) -> Coil {
        match self {
            Coil::On => Coil::Off,
            Coil::Off => Coil::On,
        }
    }
}

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

    #[test]
    fn test_coil_booleanness() {
        let a: Coil = true.into();
        assert_ne!(a, !a);
        assert_eq!(a, !!a);
        let b: Coil = false.into();
        assert_eq!(a, !b);
    }
}
<|endoftext|>


<commit_before>//! This is a library for controlling a cursor and a screen,
//! on ANSI terminals.
//!
//!
//! ## Example
//!
//!     use ansi_control::*;
//!

/// A Pos is position of clearing (display|line) from cursor.
pub enum Pos {
    Back,
    Front,
    Both,
}

/// Moves the cursor _i_ (row), _j_ (column) cells. If the cursor
/// is already at the edge of the screen, this has no effect.
pub fn move_cursor(i: i32, j: i32) -> String {
    format!("")
}

/// Moves the cursor to beginning of the line _n_ lines down.
/// If _n_ is a negative number, this function moves the cursor
/// _|n|_ lines up.
pub fn move_line(n: i32) -> String {
    format!("")
}

/// Sets the column of the cursor. (n: column)
pub fn set_column(n: u32) -> String {
    format!("")
}

/// Sets the position of the cursor. (i: row, j: column)
pub fn set_position(i: u32, j: u32) -> String {
    format!("")
}

/// Clears part of screen. If pos is Pos::Back, clear from cursor
/// to the end of the screen. If pos is Pos::Front, clear from
/// cursor to beginning of the screen. If pos is Pos::Both, clear
/// entire screen.
pub fn clear_display(pos: Pos) -> String {
    format!("")
}

/// Clears part of line. If pos is Pos::Back, clear from cursor
/// to the end of the line. If pos is Pos::Front, clear from
/// cursor to beginning of the line. If pos is Pos::Both, clear
/// entire line.
pub fn clear_line(pos: Pos) -> String {
    format!("")
}

/// Scroll whole page up by _n_ lines. If _n_ is a negative
/// number, this function scroll whole page down by _|n|_ lines.
pub fn scroll(n: i32) -> String {
    format!("")
}

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

    macro_rules! test {
        ($name: ident; $ctrl: expr => $result: expr) => {
            #[test]
            fn $name() {
                assert_eq!($result, $ctrl)
            }
        };
    }

    test!(move_cursor0; move_cursor(2, -4) => "\x1B[2A\x1B[4D");
    test!(move_cursor1; move_cursor(-2, 0) => "\x1B[2B");
    test!(move_cursor2; move_cursor(0, 6) => "\x1B[6C");
    test!(move_cursor3; move_cursor(0, 0) => "");

    test!(move_line0; move_line(4) => "\x1B[4E");
    test!(move_line1; move_line(-4) => "\x1B[4F");

    test!(set_column0; set_column(3) => "\x1B[3G");
    test!(set_column1; set_column(0) => "\x1B[1G");

    test!(set_position0; set_position(3, 5) => "\x1B[3;5H");
    test!(set_position1; set_position(0, 0) => "\x1B[1;1H");

    test!(clear_display0; clear_display(Pos::Back) => "\x1B[0J");
    test!(clear_display1; clear_display(Pos::Front) => "\x1B[1J");
    test!(clear_display2; clear_display(Pos::Both) => "\x1B[2J");

    test!(clear_line0; clear_line(Pos::Back) => "\x1B[0K");
    test!(clear_line1; clear_line(Pos::Front) => "\x1B[1K");
    test!(clear_line2; clear_line(Pos::Both) => "\x1B[2K");

    test!(scroll0; scroll(7) => "\x1B[7S");
    test!(scroll1; scroll(-5) => "\x1B[5T");
}
<commit_msg>Improve move_cursor<commit_after>//! This is a library for controlling a cursor and a screen,
//! on ANSI terminals.
//!
//!
//! ## Example
//!
//!     use ansi_control::*;
//!

use std::cmp::Ordering;

/// A Pos is position of clearing (display|line) from cursor.
pub enum Pos {
    Back,
    Front,
    Both,
}

/// Moves the cursor _i_ (row), _j_ (column) cells. If the cursor
/// is already at the edge of the screen, this has no effect.
pub fn move_cursor(i: i32, j: i32) -> String {
    let code0 = match i.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}B", -i),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}A", i),
    };
    let code1 = match j.cmp(&0) {
        Ordering::Less      => format!("\x1B[{}D", -j),
        Ordering::Equal     => format!(""),
        Ordering::Greater   => format!("\x1B[{}C", j),
    };
    format!("{}{}", code0, code1)
}

/// Moves the cursor to beginning of the line _n_ lines down.
/// If _n_ is a negative number, this function moves the cursor
/// _|n|_ lines up.
pub fn move_line(n: i32) -> String {
    format!("")
}

/// Sets the column of the cursor. (n: column)
pub fn set_column(n: u32) -> String {
    format!("")
}

/// Sets the position of the cursor. (i: row, j: column)
pub fn set_position(i: u32, j: u32) -> String {
    format!("")
}

/// Clears part of screen. If pos is Pos::Back, clear from cursor
/// to the end of the screen. If pos is Pos::Front, clear from
/// cursor to beginning of the screen. If pos is Pos::Both, clear
/// entire screen.
pub fn clear_display(pos: Pos) -> String {
    format!("")
}

/// Clears part of line. If pos is Pos::Back, clear from cursor
/// to the end of the line. If pos is Pos::Front, clear from
/// cursor to beginning of the line. If pos is Pos::Both, clear
/// entire line.
pub fn clear_line(pos: Pos) -> String {
    format!("")
}

/// Scroll whole page up by _n_ lines. If _n_ is a negative
/// number, this function scroll whole page down by _|n|_ lines.
pub fn scroll(n: i32) -> String {
    format!("")
}

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

    macro_rules! test {
        ($name: ident; $ctrl: expr => $result: expr) => {
            #[test]
            fn $name() {
                assert_eq!($result, $ctrl)
            }
        };
    }

    test!(move_cursor0; move_cursor(2, -4) => "\x1B[2A\x1B[4D");
    test!(move_cursor1; move_cursor(-2, 0) => "\x1B[2B");
    test!(move_cursor2; move_cursor(0, 6) => "\x1B[6C");
    test!(move_cursor3; move_cursor(0, 0) => "");

    test!(move_line0; move_line(4) => "\x1B[4E");
    test!(move_line1; move_line(-4) => "\x1B[4F");

    test!(set_column0; set_column(3) => "\x1B[3G");
    test!(set_column1; set_column(0) => "\x1B[1G");

    test!(set_position0; set_position(3, 5) => "\x1B[3;5H");
    test!(set_position1; set_position(0, 0) => "\x1B[1;1H");

    test!(clear_display0; clear_display(Pos::Back) => "\x1B[0J");
    test!(clear_display1; clear_display(Pos::Front) => "\x1B[1J");
    test!(clear_display2; clear_display(Pos::Both) => "\x1B[2J");

    test!(clear_line0; clear_line(Pos::Back) => "\x1B[0K");
    test!(clear_line1; clear_line(Pos::Front) => "\x1B[1K");
    test!(clear_line2; clear_line(Pos::Both) => "\x1B[2K");

    test!(scroll0; scroll(7) => "\x1B[7S");
    test!(scroll1; scroll(-5) => "\x1B[5T");
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! Operations on ASCII strings and characters

#![feature(macro_rules, globs, default_type_params)]
#![unstable = "unsure about placement and naming"]
#![allow(deprecated)]

//use std::kinds::Sized;
use std::fmt;
use std::mem;
use std::borrow::BorrowFrom;
use std::ascii::AsciiExt;

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
pub struct Ascii { chr: u8 }

impl Ascii {
    /// Converts an ascii character into a `u8`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_byte(&self) -> u8 {
        self.chr
    }

    /// Converts an ascii character into a `char`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_char(&self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline]
    #[stable]
    pub fn to_lowercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_lowercase()}
    }

    /// Convert to uppercase.
    #[inline]
    #[stable]
    pub fn to_uppercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_uppercase()}
    }

    // the following methods are like ctype, and the implementation is inspired by musl

    /// Check if the character is a letter (a-z, A-Z)
    #[inline]
    #[stable]
    pub fn is_alphabetic(&self) -> bool {
        (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
    }

    /// Check if the character is a number (0-9)
    #[inline]
    #[unstable = "may be renamed"]
    pub fn is_digit(&self) -> bool {
        self.chr >= 0x30 && self.chr <= 0x39
    }

    /// Check if the character is a letter or number
    #[inline]
    #[stable]
    pub fn is_alphanumeric(&self) -> bool {
        self.is_alphabetic() || self.is_digit()
    }

    /// Check if the character is a space or horizontal tab
    #[inline]
    #[experimental = "likely to be removed"]
    pub fn is_blank(&self) -> bool {
        self.chr == b' ' || self.chr == b'\t'
    }

    /// Check if the character is a control character
    #[inline]
    #[stable]
    pub fn is_control(&self) -> bool {
        self.chr < 0x20 || self.chr == 0x7F
    }

    /// Checks if the character is printable (except space)
    #[inline]
    #[experimental = "unsure about naming, or whether this is needed"]
    pub fn is_graph(&self) -> bool {
        (self.chr - 0x21) < 0x5E
    }

    /// Checks if the character is printable (including space)
    #[inline]
    #[unstable = "unsure about naming"]
    pub fn is_print(&self) -> bool {
        (self.chr - 0x20) < 0x5F
    }

    /// Checks if the character is alphabetic and lowercase
    #[inline]
    #[stable]
    pub fn is_lowercase(&self) -> bool {
        (self.chr - b'a') < 26
    }

    /// Checks if the character is alphabetic and uppercase
    #[inline]
    #[stable]
    pub fn is_uppercase(&self) -> bool {
        (self.chr - b'A') < 26
    }

    /// Checks if the character is punctuation
    #[inline]
    #[stable]
    pub fn is_punctuation(&self) -> bool {
        self.is_graph() && !self.is_alphanumeric()
    }

    /// Checks if the character is a valid hex digit
    #[inline]
    #[stable]
    pub fn is_hex(&self) -> bool {
        self.is_digit() || ((self.chr | 32u8) - b'a') < 6
    }
}

impl<'a> fmt::Show for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self.chr as char).fmt(f)
    }
}

/// Trait for converting into an ascii type.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiCast<T, U = Self> for Sized?: AsciiExt<U> {
    /// Convert to an ascii type, panic on non-ASCII input.
    #[inline]
    fn to_ascii(&self) -> T {
        assert!(self.is_ascii());
        unsafe {self.to_ascii_nocheck()}
    }

    /// Convert to an ascii type, return None on non-ASCII input.
    #[inline]
    fn to_ascii_opt(&self) -> Option<T> {
        if self.is_ascii() {
            Some(unsafe { self.to_ascii_nocheck() })
        } else {
            None
        }
    }

    /// Convert to an ascii type, not doing any range asserts
    unsafe fn to_ascii_nocheck(&self) -> T;
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a[Ascii], Vec<u8>> for [u8] {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a [Ascii], String> for str {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for u8 {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self }
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for char {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self as u8 }
    }
}

/// Trait for copyless casting to an ascii vector.
#[experimental = "may be replaced by generic conversion traits"]
pub trait OwnedAsciiCast<Sized? T, U = Self>
where T: BorrowFrom<Self> + AsciiExt<U> {
    /// Take ownership and cast to an ascii vector.
    /// # Panics
    ///
    /// Panic on non-ASCII input.
    #[inline]
    fn into_ascii(self) -> Vec<Ascii> {
        assert!({
            let borrowed: &T = BorrowFrom::borrow_from(&self);
            borrowed.is_ascii()
        });
        unsafe {self.into_ascii_nocheck()}
    }

    /// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
    #[inline]
    fn into_ascii_opt(self) -> Option<Vec<Ascii>> {
        if {
            let borrowed: &T = BorrowFrom::borrow_from(&self);
            borrowed.is_ascii()
        } {
            Some(unsafe { self.into_ascii_nocheck() })
        } else {
            None
        }
    }

    /// Take ownership and cast to an ascii vector.
    /// Does not perform validation checks.
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<str> for String {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        self.into_bytes().into_ascii_nocheck()
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<[u8]> for Vec<u8> {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        let v = Vec::from_raw_parts(self.as_ptr() as *mut Ascii,
                                    self.len(),
                                    self.capacity());

        // We forget `self` to avoid freeing it at the end of the scope
        // Otherwise, the returned `Vec` would point to freed memory
        mem::forget(self);
        v
    }
}

/// Trait for converting an ascii type to a string. Needed to convert
/// `&[Ascii]` to `&str`.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiStr for Sized? {
    /// Convert to a string.
    fn as_str<'a>(&'a self) -> &'a str;

    /// Convert to bytes.
    fn as_bytes<'a>(&'a self) -> &'a [u8];
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiStr for [Ascii] {
    #[inline]
    fn as_str<'a>(&'a self) -> &'a str {
        unsafe { mem::transmute(self) }
    }

    #[inline]
    fn as_bytes<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(self) }
    }
}

impl IntoString for Vec<Ascii> {
    #[inline]
    fn into_string(self) -> String {
        unsafe { String::from_utf8_unchecked(self.into_bytes()) }
    }
}

/// Trait to convert to an owned byte vector by consuming self
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoBytes {
    /// Converts to an owned byte vector by consuming self
    fn into_bytes(self) -> Vec<u8>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl IntoBytes for Vec<Ascii> {
    fn into_bytes(self) -> Vec<u8> {
        unsafe {
            let v = Vec::from_raw_parts(self.as_ptr() as *mut u8,
                                        self.len(),
                                        self.capacity());

            // We forget `self` to avoid freeing it at the end of the scope
            // Otherwise, the returned `Vec` would point to freed memory
            mem::forget(self);
            v
        }
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
        (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
    )

    macro_rules! vec2ascii (
        ($($e:expr),*) => ([$(Ascii{chr:$e}),*].to_vec());
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii().as_byte(), 65u8);
        assert_eq!(65u8.to_ascii().as_char(), 'A');
        assert_eq!('A'.to_ascii().as_char(), 'A');
        assert_eq!('A'.to_ascii().as_byte(), 65u8);

        assert!('0'.to_ascii().is_digit());
        assert!('9'.to_ascii().is_digit());
        assert!(!'/'.to_ascii().is_digit());
        assert!(!':'.to_ascii().is_digit());

        assert!((0x1fu8).to_ascii().is_control());
        assert!(!' '.to_ascii().is_control());
        assert!((0x7fu8).to_ascii().is_control());
    }

    #[test]
    fn test_ascii_vec() {
        let test = &[40u8, 32u8, 59u8];
        let b: &[_] = v2ascii!([40, 32, 59]);
        assert_eq!(test.to_ascii(), b);
        assert_eq!("( ;".to_ascii(), b);
        let v = vec![40u8, 32u8, 59u8];
        assert_eq!(v.as_slice().to_ascii(), b);
        assert_eq!("( ;".to_string().as_slice().to_ascii(), b);
    }

    #[test]
    fn test_owned_ascii_vec() {
        assert_eq!(("( ;".to_string()).into_ascii(), vec2ascii![40, 32, 59]);
        assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii(), vec2ascii![40, 32, 59]);
    }

    #[test]
    fn test_ascii_as_str() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_str(), "( ;");
    }

    #[test]
    fn test_ascii_as_bytes() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_bytes(), b"( ;");
    }

    #[test]
    fn test_ascii_into_string() {
        assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
        assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
    }

    #[test]
    fn test_ascii_to_bytes() {
        assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
    }

    #[test] #[should_fail]
    fn test_ascii_vec_panic_u8_slice()  { (&[127u8, 128u8, 255u8]).to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_vec_panic_str_slice() { "zoä华".to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_panic_u8_slice() { 255u8.to_ascii(); }

    #[test] #[should_fail]
    fn test_ascii_panic_char_slice() { 'λ'.to_ascii(); }

    #[test]
    fn test_opt() {
        assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
        assert_eq!(255u8.to_ascii_opt(), None);

        assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
        assert_eq!('λ'.to_ascii_opt(), None);

        assert_eq!("zoä华".to_ascii_opt(), None);

        let test1 = &[127u8, 128u8, 255u8];
        assert_eq!((test1).to_ascii_opt(), None);

        let v = [40u8, 32u8, 59u8];
        let v2: &[_] = v2ascii!(&[40, 32, 59]);
        assert_eq!(v.to_ascii_opt(), Some(v2));
        let v = [127u8, 128u8, 255u8];
        assert_eq!(v.to_ascii_opt(), None);

        let v = "( ;";
        assert_eq!(v.to_ascii_opt(), Some(v2));
        assert_eq!("zoä华".to_ascii_opt(), None);

        assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
        assert_eq!((vec![127u8, 128u8, 255u8]).into_ascii_opt(), None);

        assert_eq!(("( ;".to_string()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
        assert_eq!(("zoä华".to_string()).into_ascii_opt(), None);
    }

    #[test]
    fn test_to_string() {
        let s = Ascii{ chr: b't' }.to_string();
        assert_eq!(s, "t".to_string());
    }

    #[test]
    fn test_show() {
        let c = Ascii { chr: b't' };
        assert_eq!(format!("{}", c), "t".to_string());
    }
}
<commit_msg>Remove to_ascii and into_ascii methods that panic on failure.<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// ignore-lexer-test FIXME #15679

//! Operations on ASCII strings and characters

#![feature(macro_rules, globs, default_type_params)]
#![unstable = "unsure about placement and naming"]
#![allow(deprecated)]

//use std::kinds::Sized;
use std::fmt;
use std::mem;
use std::borrow::BorrowFrom;
use std::ascii::AsciiExt;

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
pub struct Ascii { chr: u8 }

impl Ascii {
    /// Converts an ascii character into a `u8`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_byte(&self) -> u8 {
        self.chr
    }

    /// Converts an ascii character into a `char`.
    #[inline]
    #[unstable = "recently renamed"]
    pub fn as_char(&self) -> char {
        self.chr as char
    }

    /// Convert to lowercase.
    #[inline]
    #[stable]
    pub fn to_lowercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_lowercase()}
    }

    /// Convert to uppercase.
    #[inline]
    #[stable]
    pub fn to_uppercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_uppercase()}
    }

    // the following methods are like ctype, and the implementation is inspired by musl

    /// Check if the character is a letter (a-z, A-Z)
    #[inline]
    #[stable]
    pub fn is_alphabetic(&self) -> bool {
        (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
    }

    /// Check if the character is a number (0-9)
    #[inline]
    #[unstable = "may be renamed"]
    pub fn is_digit(&self) -> bool {
        self.chr >= 0x30 && self.chr <= 0x39
    }

    /// Check if the character is a letter or number
    #[inline]
    #[stable]
    pub fn is_alphanumeric(&self) -> bool {
        self.is_alphabetic() || self.is_digit()
    }

    /// Check if the character is a space or horizontal tab
    #[inline]
    #[experimental = "likely to be removed"]
    pub fn is_blank(&self) -> bool {
        self.chr == b' ' || self.chr == b'\t'
    }

    /// Check if the character is a control character
    #[inline]
    #[stable]
    pub fn is_control(&self) -> bool {
        self.chr < 0x20 || self.chr == 0x7F
    }

    /// Checks if the character is printable (except space)
    #[inline]
    #[experimental = "unsure about naming, or whether this is needed"]
    pub fn is_graph(&self) -> bool {
        (self.chr - 0x21) < 0x5E
    }

    /// Checks if the character is printable (including space)
    #[inline]
    #[unstable = "unsure about naming"]
    pub fn is_print(&self) -> bool {
        (self.chr - 0x20) < 0x5F
    }

    /// Checks if the character is alphabetic and lowercase
    #[inline]
    #[stable]
    pub fn is_lowercase(&self) -> bool {
        (self.chr - b'a') < 26
    }

    /// Checks if the character is alphabetic and uppercase
    #[inline]
    #[stable]
    pub fn is_uppercase(&self) -> bool {
        (self.chr - b'A') < 26
    }

    /// Checks if the character is punctuation
    #[inline]
    #[stable]
    pub fn is_punctuation(&self) -> bool {
        self.is_graph() && !self.is_alphanumeric()
    }

    /// Checks if the character is a valid hex digit
    #[inline]
    #[stable]
    pub fn is_hex(&self) -> bool {
        self.is_digit() || ((self.chr | 32u8) - b'a') < 6
    }
}

impl<'a> fmt::Show for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self.chr as char).fmt(f)
    }
}

/// Trait for converting into an ascii type.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiCast<T, U = Self> for Sized?: AsciiExt<U> {
    /// Convert to an ascii type, return None on non-ASCII input.
    #[inline]
    fn to_ascii_opt(&self) -> Option<T> {
        if self.is_ascii() {
            Some(unsafe { self.to_ascii_nocheck() })
        } else {
            None
        }
    }

    /// Convert to an ascii type, not doing any range asserts
    unsafe fn to_ascii_nocheck(&self) -> T;
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a[Ascii], Vec<u8>> for [u8] {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl<'a> AsciiCast<&'a [Ascii], String> for str {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] {
        mem::transmute(self)
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for u8 {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self }
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiCast<Ascii> for char {
    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self as u8 }
    }
}

/// Trait for copyless casting to an ascii vector.
#[experimental = "may be replaced by generic conversion traits"]
pub trait OwnedAsciiCast<Sized? T, U = Self>
where T: BorrowFrom<Self> + AsciiExt<U> {
    /// Take ownership and cast to an ascii vector. Return None on non-ASCII input.
    #[inline]
    fn into_ascii_opt(self) -> Option<Vec<Ascii>> {
        if {
            let borrowed: &T = BorrowFrom::borrow_from(&self);
            borrowed.is_ascii()
        } {
            Some(unsafe { self.into_ascii_nocheck() })
        } else {
            None
        }
    }

    /// Take ownership and cast to an ascii vector.
    /// Does not perform validation checks.
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<str> for String {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        self.into_bytes().into_ascii_nocheck()
    }
}

#[experimental = "may be replaced by generic conversion traits"]
impl OwnedAsciiCast<[u8]> for Vec<u8> {
    #[inline]
    unsafe fn into_ascii_nocheck(self) -> Vec<Ascii> {
        let v = Vec::from_raw_parts(self.as_ptr() as *mut Ascii,
                                    self.len(),
                                    self.capacity());

        // We forget `self` to avoid freeing it at the end of the scope
        // Otherwise, the returned `Vec` would point to freed memory
        mem::forget(self);
        v
    }
}

/// Trait for converting an ascii type to a string. Needed to convert
/// `&[Ascii]` to `&str`.
#[experimental = "may be replaced by generic conversion traits"]
pub trait AsciiStr for Sized? {
    /// Convert to a string.
    fn as_str<'a>(&'a self) -> &'a str;

    /// Convert to bytes.
    fn as_bytes<'a>(&'a self) -> &'a [u8];
}

#[experimental = "may be replaced by generic conversion traits"]
impl AsciiStr for [Ascii] {
    #[inline]
    fn as_str<'a>(&'a self) -> &'a str {
        unsafe { mem::transmute(self) }
    }

    #[inline]
    fn as_bytes<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(self) }
    }
}

impl IntoString for Vec<Ascii> {
    #[inline]
    fn into_string(self) -> String {
        unsafe { String::from_utf8_unchecked(self.into_bytes()) }
    }
}

/// Trait to convert to an owned byte vector by consuming self
#[experimental = "may be replaced by generic conversion traits"]
pub trait IntoBytes {
    /// Converts to an owned byte vector by consuming self
    fn into_bytes(self) -> Vec<u8>;
}

#[experimental = "may be replaced by generic conversion traits"]
impl IntoBytes for Vec<Ascii> {
    fn into_bytes(self) -> Vec<u8> {
        unsafe {
            let v = Vec::from_raw_parts(self.as_ptr() as *mut u8,
                                        self.len(),
                                        self.capacity());

            // We forget `self` to avoid freeing it at the end of the scope
            // Otherwise, the returned `Vec` would point to freed memory
            mem::forget(self);
            v
        }
    }
}

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

    macro_rules! v2ascii (
        ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
        (&[$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]);
    )

    macro_rules! vec2ascii (
        ($($e:expr),*) => ([$(Ascii{chr:$e}),*].to_vec());
    )

    #[test]
    fn test_ascii() {
        assert_eq!(65u8.to_ascii_opt().unwrap().as_byte(), 65u8);
        assert_eq!(65u8.to_ascii_opt().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii_opt().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii_opt().unwrap().as_byte(), 65u8);

        assert!('0'.to_ascii_opt().unwrap().is_digit());
        assert!('9'.to_ascii_opt().unwrap().is_digit());
        assert!(!'/'.to_ascii_opt().unwrap().is_digit());
        assert!(!':'.to_ascii_opt().unwrap().is_digit());

        assert!((0x1fu8).to_ascii_opt().unwrap().is_control());
        assert!(!' '.to_ascii_opt().unwrap().is_control());
        assert!((0x7fu8).to_ascii_opt().unwrap().is_control());
    }

    #[test]
    fn test_ascii_vec() {
        let test = &[40u8, 32u8, 59u8];
        let b: &[_] = v2ascii!([40, 32, 59]);
        assert_eq!(test.to_ascii_opt().unwrap(), b);
        assert_eq!("( ;".to_ascii_opt().unwrap(), b);
        let v = vec![40u8, 32u8, 59u8];
        assert_eq!(v.as_slice().to_ascii_opt().unwrap(), b);
        assert_eq!("( ;".to_string().as_slice().to_ascii_opt().unwrap(), b);
    }

    #[test]
    fn test_ascii_as_str() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_str(), "( ;");
    }

    #[test]
    fn test_ascii_as_bytes() {
        let v = v2ascii!([40, 32, 59]);
        assert_eq!(v.as_bytes(), b"( ;");
    }

    #[test]
    fn test_ascii_into_string() {
        assert_eq!(vec2ascii![40, 32, 59].into_string(), "( ;".to_string());
        assert_eq!(vec2ascii!(40, 32, 59).into_string(), "( ;".to_string());
    }

    #[test]
    fn test_ascii_to_bytes() {
        assert_eq!(vec2ascii![40, 32, 59].into_bytes(), vec![40u8, 32u8, 59u8]);
    }

    #[test]
    fn test_opt() {
        assert_eq!(65u8.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
        assert_eq!(255u8.to_ascii_opt(), None);

        assert_eq!('A'.to_ascii_opt(), Some(Ascii { chr: 65u8 }));
        assert_eq!('λ'.to_ascii_opt(), None);

        assert_eq!("zoä华".to_ascii_opt(), None);

        let test1 = &[127u8, 128u8, 255u8];
        assert_eq!((test1).to_ascii_opt(), None);

        let v = [40u8, 32u8, 59u8];
        let v2: &[_] = v2ascii!(&[40, 32, 59]);
        assert_eq!(v.to_ascii_opt(), Some(v2));
        let v = [127u8, 128u8, 255u8];
        assert_eq!(v.to_ascii_opt(), None);

        let v = "( ;";
        assert_eq!(v.to_ascii_opt(), Some(v2));
        assert_eq!("zoä华".to_ascii_opt(), None);

        assert_eq!((vec![40u8, 32u8, 59u8]).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
        assert_eq!((vec![127u8, 128u8, 255u8]).into_ascii_opt(), None);

        assert_eq!(("( ;".to_string()).into_ascii_opt(), Some(vec2ascii![40, 32, 59]));
        assert_eq!(("zoä华".to_string()).into_ascii_opt(), None);
    }

    #[test]
    fn test_to_string() {
        let s = Ascii{ chr: b't' }.to_string();
        assert_eq!(s, "t".to_string());
    }

    #[test]
    fn test_show() {
        let c = Ascii { chr: b't' };
        assert_eq!(format!("{}", c), "t".to_string());
    }
}
<|endoftext|>