use crate::fcall::*;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use num_traits::FromPrimitive;
use std::io::{Read, Result};
use std::mem;
use std::ops::{Shl, Shr};
macro_rules! decode {
    ($decoder:expr) => {
        Decodable::decode(&mut $decoder)?
    };
    ($typ:ident, $buf:expr) => {
        $typ::from_bits_truncate(decode!($buf))
    };
}
fn create_buffer(size: usize) -> Vec<u8> {
    let mut buffer = Vec::with_capacity(size);
    unsafe {
        buffer.set_len(size);
    }
    buffer
}
fn read_exact<R: Read + ?Sized>(r: &mut R, size: usize) -> Result<Vec<u8>> {
    let mut buf = create_buffer(size);
    r.read_exact(&mut buf[..]).and(Ok(buf))
}
pub struct SResult<T>(::std::io::Result<T>);
#[derive(Clone, Debug)]
pub struct Encoder<W> {
    writer: W,
    bytes: usize,
}
impl<W: WriteBytesExt> Encoder<W> {
    pub fn new(writer: W) -> Encoder<W> {
        Encoder { writer, bytes: 0 }
    }
    
    pub fn bytes_written(&self) -> usize {
        self.bytes
    }
    
    pub fn encode<T: Encodable>(&mut self, data: &T) -> Result<usize> {
        let bytes = data.encode(&mut self.writer)?;
        self.bytes += bytes;
        Ok(bytes)
    }
    
    pub fn into_inner(self) -> W {
        self.writer
    }
}
impl<'a, T: Encodable, W: WriteBytesExt> Shl<&'a T> for Encoder<W> {
    type Output = SResult<Encoder<W>>;
    fn shl(mut self, rhs: &'a T) -> Self::Output {
        match self.encode(rhs) {
            Ok(_) => SResult(Ok(self)),
            Err(e) => SResult(Err(e)),
        }
    }
}
impl<'a, T: Encodable, W: WriteBytesExt> Shl<&'a T> for SResult<Encoder<W>> {
    type Output = Self;
    fn shl(self, rhs: &'a T) -> Self::Output {
        match self.0 {
            Ok(mut encoder) => match encoder.encode(rhs) {
                Ok(_) => SResult(Ok(encoder)),
                Err(e) => SResult(Err(e)),
            },
            Err(e) => SResult(Err(e)),
        }
    }
}
#[derive(Clone, Debug)]
pub struct Decoder<R> {
    reader: R,
}
impl<R: ReadBytesExt> Decoder<R> {
    pub fn new(reader: R) -> Decoder<R> {
        Decoder { reader }
    }
    pub fn decode<T: Decodable>(&mut self) -> Result<T> {
        Decodable::decode(&mut self.reader)
    }
    
    pub fn into_inner(self) -> R {
        self.reader
    }
}
impl<'a, T: Decodable, R: ReadBytesExt> Shr<&'a mut T> for Decoder<R> {
    type Output = SResult<Decoder<R>>;
    fn shr(mut self, rhs: &'a mut T) -> Self::Output {
        match self.decode() {
            Ok(r) => {
                *rhs = r;
                SResult(Ok(self))
            }
            Err(e) => SResult(Err(e)),
        }
    }
}
impl<'a, T: Decodable, R: ReadBytesExt> Shr<&'a mut T> for SResult<Decoder<R>> {
    type Output = Self;
    fn shr(self, rhs: &'a mut T) -> Self::Output {
        match self.0 {
            Ok(mut decoder) => match decoder.decode() {
                Ok(r) => {
                    *rhs = r;
                    SResult(Ok(decoder))
                }
                Err(e) => SResult(Err(e)),
            },
            Err(e) => SResult(Err(e)),
        }
    }
}
pub trait Encodable {
    
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize>;
}
impl Encodable for u8 {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        w.write_u8(*self).and(Ok(mem::size_of::<Self>()))
    }
}
impl Encodable for u16 {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        w.write_u16::<LittleEndian>(*self)
            .and(Ok(mem::size_of::<Self>()))
    }
}
impl Encodable for u32 {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        w.write_u32::<LittleEndian>(*self)
            .and(Ok(mem::size_of::<Self>()))
    }
}
impl Encodable for u64 {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        w.write_u64::<LittleEndian>(*self)
            .and(Ok(mem::size_of::<Self>()))
    }
}
impl Encodable for String {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        let mut bytes = (self.len() as u16).encode(w)?;
        bytes += w.write_all(self.as_bytes()).and(Ok(self.len()))?;
        Ok(bytes)
    }
}
impl Encodable for Qid {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match Encoder::new(w) << &self.typ.bits() << &self.version << &self.path {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for Statfs {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match Encoder::new(w)
            << &self.typ
            << &self.bsize
            << &self.blocks
            << &self.bfree
            << &self.bavail
            << &self.files
            << &self.ffree
            << &self.fsid
            << &self.namelen
        {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for Time {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match Encoder::new(w) << &self.sec << &self.nsec {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for Stat {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match Encoder::new(w)
            << &self.mode
            << &self.uid
            << &self.gid
            << &self.nlink
            << &self.rdev
            << &self.size
            << &self.blksize
            << &self.blocks
            << &self.atime
            << &self.mtime
            << &self.ctime
        {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for SetAttr {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match Encoder::new(w)
            << &self.mode
            << &self.uid
            << &self.gid
            << &self.size
            << &self.atime
            << &self.mtime
        {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for DirEntry {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match Encoder::new(w) << &self.qid << &self.offset << &self.typ << &self.name {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for DirEntryData {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match self
            .data()
            .iter()
            .fold(Encoder::new(w) << &self.size(), |acc, e| acc << e)
        {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for Data {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        let size = self.0.len();
        let bytes = (size as u32).encode(w)? + size;
        w.write_all(&self.0)?;
        Ok(bytes)
    }
}
impl Encodable for Flock {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match Encoder::new(w)
            << &self.typ.bits()
            << &self.flags.bits()
            << &self.start
            << &self.length
            << &self.proc_id
            << &self.client_id
        {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for Getlock {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match Encoder::new(w)
            << &self.typ.bits()
            << &self.start
            << &self.length
            << &self.proc_id
            << &self.client_id
        {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl<T: Encodable> Encodable for Vec<T> {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        match self
            .iter()
            .fold(Encoder::new(w) << &(self.len() as u16), |acc, s| acc << s)
        {
            SResult(Ok(enc)) => Ok(enc.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
impl Encodable for Msg {
    fn encode<W: WriteBytesExt>(&self, w: &mut W) -> Result<usize> {
        use crate::Fcall::*;
        let typ = MsgType::from(&self.body);
        let buf = Encoder::new(w) << &(typ as u8) << &self.tag;
        let buf = match self.body {
            
            Rlerror { ref ecode } => buf << ecode,
            Tstatfs { ref fid } => buf << fid,
            Rstatfs { ref statfs } => buf << statfs,
            Tlopen { ref fid, ref flags } => buf << fid << flags,
            Rlopen {
                ref qid,
                ref iounit,
            } => buf << qid << iounit,
            Tlcreate {
                ref fid,
                ref name,
                ref flags,
                ref mode,
                ref gid,
            } => buf << fid << name << flags << mode << gid,
            Rlcreate {
                ref qid,
                ref iounit,
            } => buf << qid << iounit,
            Tsymlink {
                ref fid,
                ref name,
                ref symtgt,
                ref gid,
            } => buf << fid << name << symtgt << gid,
            Rsymlink { ref qid } => buf << qid,
            Tmknod {
                ref dfid,
                ref name,
                ref mode,
                ref major,
                ref minor,
                ref gid,
            } => buf << dfid << name << mode << major << minor << gid,
            Rmknod { ref qid } => buf << qid,
            Trename {
                ref fid,
                ref dfid,
                ref name,
            } => buf << fid << dfid << name,
            Rrename => buf,
            Treadlink { ref fid } => buf << fid,
            Rreadlink { ref target } => buf << target,
            Tgetattr {
                ref fid,
                ref req_mask,
            } => buf << fid << &req_mask.bits(),
            Rgetattr {
                ref valid,
                ref qid,
                ref stat,
            } => buf << &valid.bits() << qid << stat << &0u64 << &0u64 << &0u64 << &0u64,
            Tsetattr {
                ref fid,
                ref valid,
                ref stat,
            } => buf << fid << &valid.bits() << stat,
            Rsetattr => buf,
            Txattrwalk {
                ref fid,
                ref newfid,
                ref name,
            } => buf << fid << newfid << name,
            Rxattrwalk { ref size } => buf << size,
            Txattrcreate {
                ref fid,
                ref name,
                ref attr_size,
                ref flags,
            } => buf << fid << name << attr_size << flags,
            Rxattrcreate => buf,
            Treaddir {
                ref fid,
                ref offset,
                ref count,
            } => buf << fid << offset << count,
            Rreaddir { ref data } => buf << data,
            Tfsync { ref fid } => buf << fid,
            Rfsync => buf,
            Tlock { ref fid, ref flock } => buf << fid << flock,
            Rlock { ref status } => buf << &status.bits(),
            Tgetlock { ref fid, ref flock } => buf << fid << flock,
            Rgetlock { ref flock } => buf << flock,
            Tlink {
                ref dfid,
                ref fid,
                ref name,
            } => buf << dfid << fid << name,
            Rlink => buf,
            Tmkdir {
                ref dfid,
                ref name,
                ref mode,
                ref gid,
            } => buf << dfid << name << mode << gid,
            Rmkdir { ref qid } => buf << qid,
            Trenameat {
                ref olddirfid,
                ref oldname,
                ref newdirfid,
                ref newname,
            } => buf << olddirfid << oldname << newdirfid << newname,
            Rrenameat => buf,
            Tunlinkat {
                ref dirfd,
                ref name,
                ref flags,
            } => buf << dirfd << name << flags,
            Runlinkat => buf,
            
            Tauth {
                ref afid,
                ref uname,
                ref aname,
                ref n_uname,
            } => buf << afid << uname << aname << n_uname,
            Rauth { ref aqid } => buf << aqid,
            Tattach {
                ref fid,
                ref afid,
                ref uname,
                ref aname,
                ref n_uname,
            } => buf << fid << afid << uname << aname << n_uname,
            Rattach { ref qid } => buf << qid,
            
            Tversion {
                ref msize,
                ref version,
            } => buf << msize << version,
            Rversion {
                ref msize,
                ref version,
            } => buf << msize << version,
            Tflush { ref oldtag } => buf << oldtag,
            Rflush => buf,
            Twalk {
                ref fid,
                ref newfid,
                ref wnames,
            } => buf << fid << newfid << wnames,
            Rwalk { ref wqids } => buf << wqids,
            Tread {
                ref fid,
                ref offset,
                ref count,
            } => buf << fid << offset << count,
            Rread { ref data } => buf << data,
            Twrite {
                ref fid,
                ref offset,
                ref data,
            } => buf << fid << offset << data,
            Rwrite { ref count } => buf << count,
            Tclunk { ref fid } => buf << fid,
            Rclunk => buf,
            Tremove { ref fid } => buf << fid,
            Rremove => buf,
        };
        match buf {
            SResult(Ok(b)) => Ok(b.bytes_written()),
            SResult(Err(e)) => Err(e),
        }
    }
}
pub trait Decodable: Sized {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self>;
}
impl Decodable for u8 {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        r.read_u8()
    }
}
impl Decodable for u16 {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        r.read_u16::<LittleEndian>()
    }
}
impl Decodable for u32 {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        r.read_u32::<LittleEndian>()
    }
}
impl Decodable for u64 {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        r.read_u64::<LittleEndian>()
    }
}
impl Decodable for String {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        let len: u16 = Decodable::decode(r)?;
        String::from_utf8(read_exact(r, len as usize)?)
            .or(res!(io_err!(Other, "Invalid UTF-8 sequence")))
    }
}
impl Decodable for Qid {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        Ok(Qid {
            typ: decode!(QidType, *r),
            version: Decodable::decode(r)?,
            path: Decodable::decode(r)?,
        })
    }
}
impl Decodable for Statfs {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        Ok(Statfs {
            typ: Decodable::decode(r)?,
            bsize: Decodable::decode(r)?,
            blocks: Decodable::decode(r)?,
            bfree: Decodable::decode(r)?,
            bavail: Decodable::decode(r)?,
            files: Decodable::decode(r)?,
            ffree: Decodable::decode(r)?,
            fsid: Decodable::decode(r)?,
            namelen: Decodable::decode(r)?,
        })
    }
}
impl Decodable for Time {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        Ok(Time {
            sec: Decodable::decode(r)?,
            nsec: Decodable::decode(r)?,
        })
    }
}
impl Decodable for Stat {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        Ok(Stat {
            mode: Decodable::decode(r)?,
            uid: Decodable::decode(r)?,
            gid: Decodable::decode(r)?,
            nlink: Decodable::decode(r)?,
            rdev: Decodable::decode(r)?,
            size: Decodable::decode(r)?,
            blksize: Decodable::decode(r)?,
            blocks: Decodable::decode(r)?,
            atime: Decodable::decode(r)?,
            mtime: Decodable::decode(r)?,
            ctime: Decodable::decode(r)?,
        })
    }
}
impl Decodable for SetAttr {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        Ok(SetAttr {
            mode: Decodable::decode(r)?,
            uid: Decodable::decode(r)?,
            gid: Decodable::decode(r)?,
            size: Decodable::decode(r)?,
            atime: Decodable::decode(r)?,
            mtime: Decodable::decode(r)?,
        })
    }
}
impl Decodable for DirEntry {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        Ok(DirEntry {
            qid: Decodable::decode(r)?,
            offset: Decodable::decode(r)?,
            typ: Decodable::decode(r)?,
            name: Decodable::decode(r)?,
        })
    }
}
impl Decodable for DirEntryData {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        let count: u32 = Decodable::decode(r)?;
        let mut data: Vec<DirEntry> = Vec::with_capacity(count as usize);
        for _ in 0..count {
            data.push(Decodable::decode(r)?);
        }
        Ok(DirEntryData::with(data))
    }
}
impl Decodable for Data {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        let len: u32 = Decodable::decode(r)?;
        Ok(Data(read_exact(r, len as usize)?))
    }
}
impl Decodable for Flock {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        Ok(Flock {
            typ: decode!(LockType, *r),
            flags: decode!(LockFlag, *r),
            start: Decodable::decode(r)?,
            length: Decodable::decode(r)?,
            proc_id: Decodable::decode(r)?,
            client_id: Decodable::decode(r)?,
        })
    }
}
impl Decodable for Getlock {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        Ok(Getlock {
            typ: decode!(LockType, *r),
            start: Decodable::decode(r)?,
            length: Decodable::decode(r)?,
            proc_id: Decodable::decode(r)?,
            client_id: Decodable::decode(r)?,
        })
    }
}
impl<T: Decodable> Decodable for Vec<T> {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        let len: u16 = Decodable::decode(r)?;
        let mut buf = Vec::new();
        for _ in 0..len {
            buf.push(Decodable::decode(r)?);
        }
        Ok(buf)
    }
}
impl Decodable for Msg {
    fn decode<R: ReadBytesExt>(r: &mut R) -> Result<Self> {
        use crate::MsgType::*;
        let mut buf = r;
        let msg_type = MsgType::from_u8(decode!(buf));
        let tag = decode!(buf);
        let body = match msg_type {
            
            Some(Rlerror) => Fcall::Rlerror {
                ecode: decode!(buf),
            },
            Some(Tstatfs) => Fcall::Tstatfs { fid: decode!(buf) },
            Some(Rstatfs) => Fcall::Rstatfs {
                statfs: decode!(buf),
            },
            Some(Tlopen) => Fcall::Tlopen {
                fid: decode!(buf),
                flags: decode!(buf),
            },
            Some(Rlopen) => Fcall::Rlopen {
                qid: decode!(buf),
                iounit: decode!(buf),
            },
            Some(Tlcreate) => Fcall::Tlcreate {
                fid: decode!(buf),
                name: decode!(buf),
                flags: decode!(buf),
                mode: decode!(buf),
                gid: decode!(buf),
            },
            Some(Rlcreate) => Fcall::Rlcreate {
                qid: decode!(buf),
                iounit: decode!(buf),
            },
            Some(Tsymlink) => Fcall::Tsymlink {
                fid: decode!(buf),
                name: decode!(buf),
                symtgt: decode!(buf),
                gid: decode!(buf),
            },
            Some(Rsymlink) => Fcall::Rsymlink { qid: decode!(buf) },
            Some(Tmknod) => Fcall::Tmknod {
                dfid: decode!(buf),
                name: decode!(buf),
                mode: decode!(buf),
                major: decode!(buf),
                minor: decode!(buf),
                gid: decode!(buf),
            },
            Some(Rmknod) => Fcall::Rmknod { qid: decode!(buf) },
            Some(Trename) => Fcall::Trename {
                fid: decode!(buf),
                dfid: decode!(buf),
                name: decode!(buf),
            },
            Some(Rrename) => Fcall::Rrename,
            Some(Treadlink) => Fcall::Treadlink { fid: decode!(buf) },
            Some(Rreadlink) => Fcall::Rreadlink {
                target: decode!(buf),
            },
            Some(Tgetattr) => Fcall::Tgetattr {
                fid: decode!(buf),
                req_mask: decode!(GetattrMask, buf),
            },
            Some(Rgetattr) => {
                let r = Fcall::Rgetattr {
                    valid: decode!(GetattrMask, buf),
                    qid: decode!(buf),
                    stat: decode!(buf),
                };
                let (_btime, _gen, _ver): (Time, u64, u64) =
                    (decode!(buf), decode!(buf), decode!(buf));
                r
            }
            Some(Tsetattr) => Fcall::Tsetattr {
                fid: decode!(buf),
                valid: decode!(SetattrMask, buf),
                stat: decode!(buf),
            },
            Some(Rsetattr) => Fcall::Rsetattr,
            Some(Txattrwalk) => Fcall::Txattrwalk {
                fid: decode!(buf),
                newfid: decode!(buf),
                name: decode!(buf),
            },
            Some(Rxattrwalk) => Fcall::Rxattrwalk { size: decode!(buf) },
            Some(Txattrcreate) => Fcall::Txattrcreate {
                fid: decode!(buf),
                name: decode!(buf),
                attr_size: decode!(buf),
                flags: decode!(buf),
            },
            Some(Rxattrcreate) => Fcall::Rxattrcreate,
            Some(Treaddir) => Fcall::Treaddir {
                fid: decode!(buf),
                offset: decode!(buf),
                count: decode!(buf),
            },
            Some(Rreaddir) => Fcall::Rreaddir { data: decode!(buf) },
            Some(Tfsync) => Fcall::Tfsync { fid: decode!(buf) },
            Some(Rfsync) => Fcall::Rfsync,
            Some(Tlock) => Fcall::Tlock {
                fid: decode!(buf),
                flock: decode!(buf),
            },
            Some(Rlock) => Fcall::Rlock {
                status: decode!(LockStatus, buf),
            },
            Some(Tgetlock) => Fcall::Tgetlock {
                fid: decode!(buf),
                flock: decode!(buf),
            },
            Some(Rgetlock) => Fcall::Rgetlock {
                flock: decode!(buf),
            },
            Some(Tlink) => Fcall::Tlink {
                dfid: decode!(buf),
                fid: decode!(buf),
                name: decode!(buf),
            },
            Some(Rlink) => Fcall::Rlink,
            Some(Tmkdir) => Fcall::Tmkdir {
                dfid: decode!(buf),
                name: decode!(buf),
                mode: decode!(buf),
                gid: decode!(buf),
            },
            Some(Rmkdir) => Fcall::Rmkdir { qid: decode!(buf) },
            Some(Trenameat) => Fcall::Trenameat {
                olddirfid: decode!(buf),
                oldname: decode!(buf),
                newdirfid: decode!(buf),
                newname: decode!(buf),
            },
            Some(Rrenameat) => Fcall::Rrenameat,
            Some(Tunlinkat) => Fcall::Tunlinkat {
                dirfd: decode!(buf),
                name: decode!(buf),
                flags: decode!(buf),
            },
            Some(Runlinkat) => Fcall::Runlinkat,
            
            Some(Tauth) => Fcall::Tauth {
                afid: decode!(buf),
                uname: decode!(buf),
                aname: decode!(buf),
                n_uname: decode!(buf),
            },
            Some(Rauth) => Fcall::Rauth { aqid: decode!(buf) },
            Some(Tattach) => Fcall::Tattach {
                fid: decode!(buf),
                afid: decode!(buf),
                uname: decode!(buf),
                aname: decode!(buf),
                n_uname: decode!(buf),
            },
            Some(Rattach) => Fcall::Rattach { qid: decode!(buf) },
            
            Some(Tversion) => Fcall::Tversion {
                msize: decode!(buf),
                version: decode!(buf),
            },
            Some(Rversion) => Fcall::Rversion {
                msize: decode!(buf),
                version: decode!(buf),
            },
            Some(Tflush) => Fcall::Tflush {
                oldtag: decode!(buf),
            },
            Some(Rflush) => Fcall::Rflush,
            Some(Twalk) => Fcall::Twalk {
                fid: decode!(buf),
                newfid: decode!(buf),
                wnames: decode!(buf),
            },
            Some(Rwalk) => Fcall::Rwalk {
                wqids: decode!(buf),
            },
            Some(Tread) => Fcall::Tread {
                fid: decode!(buf),
                offset: decode!(buf),
                count: decode!(buf),
            },
            Some(Rread) => Fcall::Rread { data: decode!(buf) },
            Some(Twrite) => Fcall::Twrite {
                fid: decode!(buf),
                offset: decode!(buf),
                data: decode!(buf),
            },
            Some(Rwrite) => Fcall::Rwrite {
                count: decode!(buf),
            },
            Some(Tclunk) => Fcall::Tclunk { fid: decode!(buf) },
            Some(Rclunk) => Fcall::Rclunk,
            Some(Tremove) => Fcall::Tremove { fid: decode!(buf) },
            Some(Rremove) => Fcall::Rremove,
            Some(Tlerror) | None => return res!(io_err!(Other, "Invalid message type")),
        };
        Ok(Msg { tag, body })
    }
}
pub fn read_msg<R: ReadBytesExt>(r: &mut R) -> Result<Msg> {
    Decodable::decode(r)
}
pub fn write_msg<W: WriteBytesExt>(w: &mut W, msg: &Msg) -> Result<usize> {
    msg.encode(w)
}
#[test]
fn encoder_test1() {
    let expected: Vec<u8> = (0..10).collect();
    let mut encoder = Vec::new();
    for i in 0..10 {
        (&(i as u8)).encode(&mut encoder).unwrap();
    }
    assert_eq!(expected, encoder);
}
#[test]
fn decoder_test1() {
    use std::io::Cursor;
    let expected: Vec<u8> = (0..10).collect();
    let mut decoder = Cursor::new(expected.clone());
    let mut actual: Vec<u8> = Vec::new();
    loop {
        match Decodable::decode(&mut decoder) {
            Ok(i) => actual.push(i),
            Err(_) => break,
        }
    }
    assert_eq!(expected, actual);
}
#[test]
fn msg_encode_decode1() {
    use std::io::Cursor;
    let expected = Msg {
        tag: 0xdead,
        body: Fcall::Rversion {
            msize: 40,
            version: P92000L.to_owned(),
        },
    };
    let mut buf = Vec::new();
    let _ = expected.encode(&mut buf);
    let mut readbuf = Cursor::new(buf);
    let actual = Decodable::decode(&mut readbuf);
    assert_eq!(expected, actual.unwrap());
}