<commit_before>//! Read and write NDArrays as Numpy arrays

use ndarray::prelude::*;
use ndarray as nd;
use std::fs::File;
use std::path::Path;
use std::ptr;
use std::str;
use std::io::{Read, Write};
use regex::bytes::Regex;
use byteorder::{LittleEndian, BigEndian, ReadBytesExt, WriteBytesExt};
use errors::*;
use memmap::{Mmap, Protection};

/// Write an array as a numpy array, fast but only works for native byte order
pub fn write_matrix<S, P>(path: P, arr: &ArrayBase<S, Ix2>) -> Result<()>
    where S: nd::Data<Elem=f64>, P: AsRef<Path> {
    let header_nospace = format!("{{'descr': '<f8', 'fortran_order': False, 'shape': ({},{})}}",
        arr.shape()[0], arr.shape()[1]);
    let virtual_len =
        // Calculating how many bytes we have in the header, so we can get alignment
        header_nospace.len()
        + 6 // The magic string
        + 2 // The version number
        + 2 // An unsigned 2-byte integer for header length
        + 1 ; // Because there will be a \n added
    let padding_needed = (((virtual_len + 15) / 16) * 16) - virtual_len; // to get to the next 16

    // Numpy version 1.0
    let mut writer = File::create(path)?;
    writer.write_all(b"\x93NUMPY\x01\x00")?;
    writer.write_u16::<LittleEndian>((header_nospace.len()
        + padding_needed
        + 1) // newline
        // Magic string, version number and 2 bytes for the header length number not included.
        as u16
        )?;
    write!(writer, "{}{}\n", header_nospace, " ".repeat(padding_needed))?;
    unsafe {
        // O(N) array copy without memory overhead.
        assert!(arr.is_standard_layout(), "To write an array it needs to be in C order (for now).");
        // Treat the incoming data as floating point
        writer.write_all(::std::slice::from_raw_parts(arr.as_ptr() as *const u8, arr.len()*8))?;
    };
    Ok(())
}

/// Read a Numpy matrix into memory. Be careful if it's large. You could run out of memory.
///
/// You need to know the number of dimensions at compile time so for convenience, we assume you
/// need a matrix. Also, this method is fast but only works for native byte order.
pub fn read_matrix<P: AsRef<Path>>(path: P) -> Result<Array2<f64>> {
    let header_match = Regex::new(r"NUMPY\x01\x00(?s:..)\{'descr': ?'<f8', ?'fortran_order': ?False, ?'shape': ?\((\d+), ?(\d+)\)\} *\n").unwrap();
    let mut reader = File::open(path)?;
    let mut content = vec![];
    reader.read_to_end(&mut content)?;
    // The skip and the nested context here is so that we can regex parse (with a borrow)
    // and then reuse the buffer as the array. This way there are never two copies in memory.
    let res: Result<(usize, usize, usize)> = {
        let captures = header_match.captures(&content)
            .ok_or(Error::Other("Numpy file unrecognized or not supported. \
                Cabarrus only supports big-endian 64-bit float arrays in C order.".to_string()))?;
        Ok((// where the full match ends
            captures.get(0).unwrap().end(),
            // The shape of the array as described in the metadata
            str::from_utf8(&captures[1]).unwrap().parse().unwrap(),
            str::from_utf8(&captures[2]).unwrap().parse().unwrap()
        ))
    };
    let (skip, h, w) = res?;
    let content_f64 = unsafe {
        // O(N) array copy without memory overhead.
        let length = content.len() - skip;
        assert_eq!(length, h*w*8,
            "The numpy file's array is the wrong length for a {}x{} array. \
            It should be {} elements, ({} bytes), but it is actually {} bytes.",
            h, w, h*w, h*w*8, length
        );
        ptr::copy((&content[skip..]).as_ptr(),
                  (&mut content[..length]).as_mut_ptr(),
                  length);
        content.set_len(length);
        // Treat the incoming data as floating point
        let mut out : Vec<f64> = ::std::mem::transmute(content);
        out.set_len(length/8);
        out
    };
    Ok(ArrayBase::from_shape_vec([h, w], content_f64)?)
}

pub struct MatFile(usize, usize, Mmap);

/// Load a Numpy matrix as an mmap. This only consumes address space. (Part 1)
///
/// This is a two-step process because the Mmap needs to outlive the matrix.
pub fn open_matrix_mmap<P: AsRef<Path>>(path: P) -> Result<MatFile> {
    let header_match = Regex::new(r"NUMPY\x01\x00(?s:..)\{'descr': ?'<f8', ?'fortran_order': ?False, ?'shape': ?\((\d+), ?(\d+)\)\} *\n").unwrap();
    let mut reader = File::open(path.as_ref())?;
    let mut content = Vec::with_capacity(65536);
    reader.read_exact(&mut content)?;
    // The skip and the nested context here is so that we can regex parse (with a borrow)
    // and then reuse the buffer as the array. This way there are never two copies in memory.
    let captures = header_match.captures(&content)
        .ok_or(Error::Other("Numpy file unrecognized or not supported. \
            Cabarrus only supports big-endian 64-bit float arrays in C order.".to_string()))?;
    // where the full match ends
    let skip = captures.get(0).unwrap().end();
    // The shape of the array as described in the metadata
    let h = str::from_utf8(&captures[1]).unwrap().parse().unwrap();
    let w = str::from_utf8(&captures[2]).unwrap().parse().unwrap();

    Ok(MatFile(h, w, Mmap::open_with_offset(&reader, Protection::Read, skip, h*w*8)?))
}

/// Load a Numpy matrix as an mmap (Part 2)
///
/// You need to know the number of dimensions at compile time so for convenience, we assume you
/// need a matrix. Also, this method is even faster than read_matrix but only works for native byte
/// order.
///
/// This is different than you might expect. The file you read from must outlive the array,
/// because the array is based on an mmap of that file (so that it doesn't read it into memory).
pub fn read_matrix_mmap<'t>(mmap: &'t MatFile) -> Result<ArrayView2<'t, f64>> {
    unsafe {
        let new_slice= ::std::slice::from_raw_parts(mmap.2.ptr() as *const f64, mmap.2.len()/8);
        Ok(ArrayView2::from_shape([mmap.0, mmap.1], new_slice)?)
    }
}<commit_msg>Add more helpful error messages<commit_after>//! Read and write NDArrays as Numpy arrays

use ndarray::prelude::*;
use ndarray as nd;
use std::fs::File;
use std::path::Path;
use std::ptr;
use std::str;
use std::io::{Read, Write};
use regex::bytes::Regex;
use byteorder::{LittleEndian, BigEndian, ReadBytesExt, WriteBytesExt};
use errors::*;
use memmap::{Mmap, Protection};

/// Write an array as a numpy array, fast but only works for native byte order
pub fn write_matrix<S, P>(path: P, arr: &ArrayBase<S, Ix2>) -> Result<()>
    where S: nd::Data<Elem=f64>, P: AsRef<Path> {
    let header_nospace = format!("{{'descr': '<f8', 'fortran_order': False, 'shape': ({},{})}}",
        arr.shape()[0], arr.shape()[1]);
    let virtual_len =
        // Calculating how many bytes we have in the header, so we can get alignment
        header_nospace.len()
        + 6 // The magic string
        + 2 // The version number
        + 2 // An unsigned 2-byte integer for header length
        + 1 ; // Because there will be a \n added
    let padding_needed = (((virtual_len + 15) / 16) * 16) - virtual_len; // to get to the next 16

    // Numpy version 1.0
    let mut writer = File::create(path)?;
    writer.write_all(b"\x93NUMPY\x01\x00")?;
    writer.write_u16::<LittleEndian>((header_nospace.len()
        + padding_needed
        + 1) // newline
        // Magic string, version number and 2 bytes for the header length number not included.
        as u16
        )?;
    write!(writer, "{}{}\n", header_nospace, " ".repeat(padding_needed))?;
    unsafe {
        // O(N) array copy without memory overhead.
        assert!(arr.is_standard_layout(), "To write an array it needs to be in C order (for now).");
        // Treat the incoming data as floating point
        writer.write_all(::std::slice::from_raw_parts(arr.as_ptr() as *const u8, arr.len()*8))?;
    };
    Ok(())
}

/// Read a Numpy matrix into memory. Be careful if it's large. You could run out of memory.
///
/// You need to know the number of dimensions at compile time so for convenience, we assume you
/// need a matrix. Also, this method is fast but only works for native byte order.
pub fn read_matrix<P: AsRef<Path>>(path: P) -> Result<Array2<f64>> {
    let header_match = Regex::new(r"NUMPY\x01\x00(?s:..)\{'descr': ?'<f8', ?'fortran_order': ?False, ?'shape': ?\((\d+), ?(\d+)\)\} *\n").unwrap();
    let mut reader = File::open(path.as_ref())?;
    let mut content = vec![];
    reader.read_to_end(&mut content)?;
    // The skip and the nested context here is so that we can regex parse (with a borrow)
    // and then reuse the buffer as the array. This way there are never two copies in memory.
    let res: Result<(usize, usize, usize)> = {
        let captures = header_match.captures(&content)
            .ok_or(helpful_complaint(path.as_ref(), &content))?;
        Ok((// where the full match ends
            captures.get(0).unwrap().end(),
            // The shape of the array as described in the metadata
            str::from_utf8(&captures[1]).unwrap().parse().unwrap(),
            str::from_utf8(&captures[2]).unwrap().parse().unwrap()
        ))
    };
    let (skip, h, w) = res?;
    let content_f64 = unsafe {
        // O(N) array copy without memory overhead.
        let length = content.len() - skip;
        assert_eq!(length, h*w*8,
            "The numpy file's array is the wrong length for a {}x{} array. \
            It should be {} elements, ({} bytes), but it is actually {} bytes.",
            h, w, h*w, h*w*8, length
        );
        ptr::copy((&content[skip..]).as_ptr(),
                  (&mut content[..length]).as_mut_ptr(),
                  length);
        content.set_len(length);
        // Treat the incoming data as floating point
        let mut out : Vec<f64> = ::std::mem::transmute(content);
        out.set_len(length/8);
        out
    };
    Ok(ArrayBase::from_shape_vec([h, w], content_f64)?)
}

pub struct MatFile(usize, usize, Mmap);

/// Load a Numpy matrix as an mmap. This only consumes address space. (Part 1)
///
/// This is a two-step process because the Mmap needs to outlive the matrix.
pub fn open_matrix_mmap<P: AsRef<Path>>(path: P) -> Result<MatFile> {
    let header_match = Regex::new(r"NUMPY\x01\x00(?s:..)\{'descr': ?'<f8', ?'fortran_order': ?False, ?'shape': ?\((\d+), ?(\d+)\)\} *\n").unwrap();
    let mut reader = File::open(path.as_ref())?;
    let mut content = Vec::with_capacity(65536);
    reader.read_exact(&mut content)?;
    // The skip and the nested context here is so that we can regex parse (with a borrow)
    // and then reuse the buffer as the array. This way there are never two copies in memory.
    let captures = header_match.captures(&content)
        .ok_or(helpful_complaint(path.as_ref(), &content))?;
    // where the full match ends
    let skip = captures.get(0).unwrap().end();
    // The shape of the array as described in the metadata
    let h = str::from_utf8(&captures[1]).unwrap().parse().unwrap();
    let w = str::from_utf8(&captures[2]).unwrap().parse().unwrap();

    Ok(MatFile(h, w, Mmap::open_with_offset(&reader, Protection::Read, skip, h*w*8)?))
}

/// Load a Numpy matrix as an mmap (Part 2)
///
/// You need to know the number of dimensions at compile time so for convenience, we assume you
/// need a matrix. Also, this method is even faster than read_matrix but only works for native byte
/// order.
///
/// This is different than you might expect. The file you read from must outlive the array,
/// because the array is based on an mmap of that file (so that it doesn't read it into memory).
pub fn read_matrix_mmap<'t>(mmap: &'t MatFile) -> Result<ArrayView2<'t, f64>> {
    unsafe {
        let new_slice= ::std::slice::from_raw_parts(mmap.2.ptr() as *const f64, mmap.2.len()/8);
        Ok(ArrayView2::from_shape([mmap.0, mmap.1], new_slice)?)
    }
}

/// Tell the user more info about the file
///
/// It seems verbose but you can see this error often so it save you time.
fn helpful_complaint(p: &Path, header: &[u8]) -> Error {
    let complaint = format!(
        "Expected {} to be an uncompressed numpy (.npy) file, but couldn't \
        parse the header. The first hundred bytes look like: \n\n{}\n\n\
        As bytes, the header is as follows: \n\n{:?}\n\n\
        It should look something like this example, where . are non-printable characters: \
        NUMPY..{{'descr': '<f8', 'fortran_order': False, 'shape': (34, 27)}}\
        Note: Cabarrus only supports 2D big-endian 64-bit float matrices in C order (for \
        simplicity). You may need to change the dtype accordingly.",
        p.display(),
        String::from_utf8_lossy(&header[..100]),
        &header[..100]);
    Error::Other(complaint)
}<|endoftext|>


<commit_before>// Hidden internal interface
#![allow(missing_docs)]

use bufstream::BufStream;
use convert::{FromIter, FromMap};
use error::{Error, ProtoError, Result, ParseError};

use reply::Reply;
use std::collections::BTreeMap;
use std::fmt;
use std::io::{self, Lines, Read, Write};
use std::result::Result as StdResult;
use std::str::FromStr;

pub struct Pairs<I>(pub I);

impl<I> Iterator for Pairs<I>
    where I: Iterator<Item = io::Result<String>>
{
    type Item = Result<(String, String)>;
    fn next(&mut self) -> Option<Result<(String, String)>> {
        let reply: Option<Result<Reply>> = self.0
            .next()
            .map(|v| v.map_err(Error::Io).and_then(|s| s.parse::<Reply>().map_err(Error::Parse)));
        match reply {
            Some(Ok(Reply::Pair(a, b))) => Some(Ok((a, b))),
            None |
            Some(Ok(Reply::Ok)) => None,
            Some(Ok(Reply::Ack(e))) => Some(Err(Error::Server(e))),
            Some(Err(e)) => Some(Err(e)),
        }
    }
}

pub struct Maps<'a, I: 'a> {
    pairs: &'a mut Pairs<I>,
    sep: &'a str,
    value: Option<String>,
    done: bool,
    first: bool,
}

impl<'a, I> Iterator for Maps<'a, I>
    where I: Iterator<Item = io::Result<String>>
{
    type Item = Result<BTreeMap<String, String>>;
    fn next(&mut self) -> Option<Result<BTreeMap<String, String>>> {
        if self.done {
            return None;
        }

        let mut map = BTreeMap::new();

        if let Some(b) = self.value.take() {
            map.insert(self.sep.to_owned(), b);
        }

        loop {
            match self.pairs.next() {
                Some(Ok((a, b))) => {
                    if &*a == self.sep {
                        self.value = Some(b);
                        if self.first {
                            self.first = false;
                            return self.next();
                        }
                        break;
                    } else {
                        map.insert(a, b);
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => {
                    self.done = true;
                    break;
                }
            }
        }

        if map.is_empty() { None } else { Some(Ok(map)) }
    }
}

impl<I> Pairs<I>
    where I: Iterator<Item = io::Result<String>>
{
    pub fn split<'a, 'b: 'a>(&'a mut self, f: &'b str) -> Maps<'a, I> {
        Maps {
            pairs: self,
            sep: f,
            value: None,
            done: false,
            first: true,
        }
    }
}

// Client inner communication methods {{{
#[doc(hidden)]
pub trait Proto {
    type Stream: Read + Write;

    fn read_line(&mut self) -> Result<String>;
    fn read_pairs(&mut self) -> Pairs<Lines<&mut BufStream<Self::Stream>>>;

    fn run_command<I>(&mut self, command: &str, arguments: I) -> Result<()> where I: ToArguments;

    fn read_map(&mut self) -> Result<BTreeMap<String, String>> {
        self.read_pairs().collect()
    }

    fn read_structs<'a, T>(&'a mut self, key: &'static str) -> Result<Vec<T>>
        where T: 'a + FromMap
    {
        self.read_pairs().split(key).map(|v| v.and_then(FromMap::from_map)).collect()
    }

    fn read_struct<'a, T>(&'a mut self) -> Result<T>
        where T: 'a + FromIter,
              Self::Stream: 'a
    {
        FromIter::from_iter(self.read_pairs())
    }

    fn drain(&mut self) -> Result<()> {
        loop {
            let reply = try!(self.read_line());
            match &*reply {
                "OK" | "list_OK" => break,
                _ => (),
            }
        }
        Ok(())
    }

    fn expect_ok(&mut self) -> Result<()> {
        let line = try!(self.read_line());

        match line.parse::<Reply>() {
            Ok(Reply::Ok) => Ok(()),
            Ok(Reply::Ack(e)) => Err(Error::Server(e)),
            Ok(_) => Err(Error::Proto(ProtoError::NotOk)),
            Err(e) => Err(From::from(e)),
        }
    }

    fn read_pair(&mut self) -> Result<(String, String)> {
        let line = try!(self.read_line());

        match line.parse::<Reply>() {
            Ok(Reply::Pair(a, b)) => Ok((a, b)),
            Ok(Reply::Ok) => Err(Error::Proto(ProtoError::NotPair)),
            Ok(Reply::Ack(e)) => Err(Error::Server(e)),
            Err(e) => Err(Error::Parse(e)),
        }
    }

    fn read_field<T, E>(&mut self, field: &'static str) -> Result<T>
        where T: FromStr<Err = E>,
              ParseError: From<E>
    {
        let (a, b) = self.read_pair()?;
        self.expect_ok()?;
        if &*a == field {
            Ok(b.parse::<T>().map_err(Into::<ParseError>::into)?)
        } else {
            Err(Error::Proto(ProtoError::NoField(field)))
        }
    }
}

pub trait ToArguments {
    fn to_arguments<F, E>(&self, &mut F) -> StdResult<(), E> where F: FnMut(&str) -> StdResult<(), E>;
}

impl ToArguments for () {
    fn to_arguments<F, E>(&self, _: &mut F) -> StdResult<(), E>
        where F: FnMut(&str) -> StdResult<(), E>
    {
        Ok(())
    }
}

impl<'a> ToArguments for &'a str {
    fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
        where F: FnMut(&str) -> StdResult<(), E>
    {
        f(self)
    }
}

macro_rules! argument_for_display {
    ( $x:path ) => {
        impl ToArguments for $x {
            fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
                where F: FnMut(&str) -> StdResult<(), E>
                {
                    f(&self.to_string())
                }
        }
    };
}
argument_for_display!{i8}
argument_for_display!{u8}
argument_for_display!{u32}
argument_for_display!{f32}
argument_for_display!{f64}
argument_for_display!{usize}
argument_for_display!{::status::ReplayGain}
argument_for_display!{String}
argument_for_display!{::song::Id}
argument_for_display!{::song::Range}
argument_for_display!{::message::Channel}

macro_rules! argument_for_tuple {
    ( $($t:ident: $T: ident),+ ) => {
        impl<$($T : ToArguments,)*> ToArguments for ($($T,)*) {
            fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
                where F: FnMut(&str) -> StdResult<(), E>
                {
                    let ($(ref $t,)*) = *self;
                    $(
                        $t.to_arguments(f)?;
                     )*
                    Ok(())
                }
        }
    };
}
argument_for_tuple!{t0: T0}
argument_for_tuple!{t0: T0, t1: T1}
argument_for_tuple!{t0: T0, t1: T1, t2: T2}
argument_for_tuple!{t0: T0, t1: T1, t2: T2, t3:T3}

impl<'a, T: ToArguments> ToArguments for &'a [T] {
    fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
        where F: FnMut(&str) -> StdResult<(), E>
    {
        for arg in *self {
            arg.to_arguments(f)?
        }
        Ok(())
    }
}

pub struct Quoted<'a, D: fmt::Display + 'a + ?Sized>(pub &'a D);

impl<'a, D: fmt::Display + 'a + ?Sized> fmt::Display for Quoted<'a, D> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let unquoted = format!("{}", self.0);
        if &unquoted == "" {
            // return Ok(());
        }
        let quoted = unquoted.replace('\\', r"\\").replace('"', r#"\""#);
        formatter.write_fmt(format_args!("\"{}\"", &quoted))
    }
}

// }}}
<commit_msg>Remove unused function.<commit_after>// Hidden internal interface
#![allow(missing_docs)]

use bufstream::BufStream;
use convert::{FromIter, FromMap};
use error::{Error, ProtoError, Result, ParseError};

use reply::Reply;
use std::collections::BTreeMap;
use std::fmt;
use std::io::{self, Lines, Read, Write};
use std::result::Result as StdResult;
use std::str::FromStr;

pub struct Pairs<I>(pub I);

impl<I> Iterator for Pairs<I>
    where I: Iterator<Item = io::Result<String>>
{
    type Item = Result<(String, String)>;
    fn next(&mut self) -> Option<Result<(String, String)>> {
        let reply: Option<Result<Reply>> = self.0
            .next()
            .map(|v| v.map_err(Error::Io).and_then(|s| s.parse::<Reply>().map_err(Error::Parse)));
        match reply {
            Some(Ok(Reply::Pair(a, b))) => Some(Ok((a, b))),
            None |
            Some(Ok(Reply::Ok)) => None,
            Some(Ok(Reply::Ack(e))) => Some(Err(Error::Server(e))),
            Some(Err(e)) => Some(Err(e)),
        }
    }
}

pub struct Maps<'a, I: 'a> {
    pairs: &'a mut Pairs<I>,
    sep: &'a str,
    value: Option<String>,
    done: bool,
    first: bool,
}

impl<'a, I> Iterator for Maps<'a, I>
    where I: Iterator<Item = io::Result<String>>
{
    type Item = Result<BTreeMap<String, String>>;
    fn next(&mut self) -> Option<Result<BTreeMap<String, String>>> {
        if self.done {
            return None;
        }

        let mut map = BTreeMap::new();

        if let Some(b) = self.value.take() {
            map.insert(self.sep.to_owned(), b);
        }

        loop {
            match self.pairs.next() {
                Some(Ok((a, b))) => {
                    if &*a == self.sep {
                        self.value = Some(b);
                        if self.first {
                            self.first = false;
                            return self.next();
                        }
                        break;
                    } else {
                        map.insert(a, b);
                    }
                }
                Some(Err(e)) => return Some(Err(e)),
                None => {
                    self.done = true;
                    break;
                }
            }
        }

        if map.is_empty() { None } else { Some(Ok(map)) }
    }
}

impl<I> Pairs<I>
    where I: Iterator<Item = io::Result<String>>
{
    pub fn split<'a, 'b: 'a>(&'a mut self, f: &'b str) -> Maps<'a, I> {
        Maps {
            pairs: self,
            sep: f,
            value: None,
            done: false,
            first: true,
        }
    }
}

// Client inner communication methods {{{
#[doc(hidden)]
pub trait Proto {
    type Stream: Read + Write;

    fn read_line(&mut self) -> Result<String>;
    fn read_pairs(&mut self) -> Pairs<Lines<&mut BufStream<Self::Stream>>>;

    fn run_command<I>(&mut self, command: &str, arguments: I) -> Result<()> where I: ToArguments;

    fn read_structs<'a, T>(&'a mut self, key: &'static str) -> Result<Vec<T>>
        where T: 'a + FromMap
    {
        self.read_pairs().split(key).map(|v| v.and_then(FromMap::from_map)).collect()
    }

    fn read_struct<'a, T>(&'a mut self) -> Result<T>
        where T: 'a + FromIter,
              Self::Stream: 'a
    {
        FromIter::from_iter(self.read_pairs())
    }

    fn drain(&mut self) -> Result<()> {
        loop {
            let reply = try!(self.read_line());
            match &*reply {
                "OK" | "list_OK" => break,
                _ => (),
            }
        }
        Ok(())
    }

    fn expect_ok(&mut self) -> Result<()> {
        let line = try!(self.read_line());

        match line.parse::<Reply>() {
            Ok(Reply::Ok) => Ok(()),
            Ok(Reply::Ack(e)) => Err(Error::Server(e)),
            Ok(_) => Err(Error::Proto(ProtoError::NotOk)),
            Err(e) => Err(From::from(e)),
        }
    }

    fn read_pair(&mut self) -> Result<(String, String)> {
        let line = try!(self.read_line());

        match line.parse::<Reply>() {
            Ok(Reply::Pair(a, b)) => Ok((a, b)),
            Ok(Reply::Ok) => Err(Error::Proto(ProtoError::NotPair)),
            Ok(Reply::Ack(e)) => Err(Error::Server(e)),
            Err(e) => Err(Error::Parse(e)),
        }
    }

    fn read_field<T, E>(&mut self, field: &'static str) -> Result<T>
        where T: FromStr<Err = E>,
              ParseError: From<E>
    {
        let (a, b) = self.read_pair()?;
        self.expect_ok()?;
        if &*a == field {
            Ok(b.parse::<T>().map_err(Into::<ParseError>::into)?)
        } else {
            Err(Error::Proto(ProtoError::NoField(field)))
        }
    }
}

pub trait ToArguments {
    fn to_arguments<F, E>(&self, &mut F) -> StdResult<(), E> where F: FnMut(&str) -> StdResult<(), E>;
}

impl ToArguments for () {
    fn to_arguments<F, E>(&self, _: &mut F) -> StdResult<(), E>
        where F: FnMut(&str) -> StdResult<(), E>
    {
        Ok(())
    }
}

impl<'a> ToArguments for &'a str {
    fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
        where F: FnMut(&str) -> StdResult<(), E>
    {
        f(self)
    }
}

macro_rules! argument_for_display {
    ( $x:path ) => {
        impl ToArguments for $x {
            fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
                where F: FnMut(&str) -> StdResult<(), E>
                {
                    f(&self.to_string())
                }
        }
    };
}
argument_for_display!{i8}
argument_for_display!{u8}
argument_for_display!{u32}
argument_for_display!{f32}
argument_for_display!{f64}
argument_for_display!{usize}
argument_for_display!{::status::ReplayGain}
argument_for_display!{String}
argument_for_display!{::song::Id}
argument_for_display!{::song::Range}
argument_for_display!{::message::Channel}

macro_rules! argument_for_tuple {
    ( $($t:ident: $T: ident),+ ) => {
        impl<$($T : ToArguments,)*> ToArguments for ($($T,)*) {
            fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
                where F: FnMut(&str) -> StdResult<(), E>
                {
                    let ($(ref $t,)*) = *self;
                    $(
                        $t.to_arguments(f)?;
                     )*
                    Ok(())
                }
        }
    };
}
argument_for_tuple!{t0: T0}
argument_for_tuple!{t0: T0, t1: T1}
argument_for_tuple!{t0: T0, t1: T1, t2: T2}
argument_for_tuple!{t0: T0, t1: T1, t2: T2, t3:T3}

impl<'a, T: ToArguments> ToArguments for &'a [T] {
    fn to_arguments<F, E>(&self, f: &mut F) -> StdResult<(), E>
        where F: FnMut(&str) -> StdResult<(), E>
    {
        for arg in *self {
            arg.to_arguments(f)?
        }
        Ok(())
    }
}

pub struct Quoted<'a, D: fmt::Display + 'a + ?Sized>(pub &'a D);

impl<'a, D: fmt::Display + 'a + ?Sized> fmt::Display for Quoted<'a, D> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        let unquoted = format!("{}", self.0);
        if &unquoted == "" {
            // return Ok(());
        }
        let quoted = unquoted.replace('\\', r"\\").replace('"', r#"\""#);
        formatter.write_fmt(format_args!("\"{}\"", &quoted))
    }
}

// }}}
<|endoftext|>