<commit_before>extern crate ocl;
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
#[allow(non_snake_case)]
pub mod ffi;
use std::mem;
pub use ffi::clfftSetupData;

macro_rules! clfft_try {
    ( $result_expr: expr) => {
        let result = $result_expr;
        if result != ffi::clfftStatus::CLFFT_SUCCESS {
            return ocl::Error::err_status(unsafe { mem::transmute(result) }, "FOREIGN_CLFFT_ERROR", "See http://clmathlibraries.github.io/clFFT/clFFT_8h.html#a74e303bed132064cfa22c1cce96d2bce for further information");
        }
    }
}

macro_rules! clfft_panic {
    ( $result_expr: expr) => {
        let result = $result_expr;
        if result != ffi::clfftStatus::CLFFT_SUCCESS {
            panic!("Unexpeced error in foreign library: {:?}", result);
        }
    }
}

/// Initialize the internal FFT resources such as FFT implementation caches kernels, programs, and buffers.
pub fn init_lib() -> ffi::clfftSetupData {
    let mut major: ocl::ffi::cl_uint = 0;
    let mut minor: ocl::ffi::cl_uint = 0;
    let mut patch: ocl::ffi::cl_uint = 0;
    clfft_panic!( unsafe { ffi::clfftGetVersion(&mut major, &mut minor, &mut patch) } );
    let data = ffi::clfftSetupData {
        major: major,
        minor: minor,
        patch: patch,
        debugFlags: 0,
    };

    clfft_panic!(unsafe { ffi::clfftSetup(&data) });
    data
}

/// Release all internal resources acquired during `init_lib`.
pub fn drop_lib() {
    unsafe { ffi::clfftTeardown() };
}

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

    #[test]
    pub fn fft_test() {
        init_lib();

        drop_lib();
    }
}<commit_msg>Started a plan type<commit_after>extern crate ocl;
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
#[allow(non_snake_case)]
pub mod ffi;
use std::mem;
pub use ffi::clfftSetupData;

macro_rules! clfft_try {
    ( $result_expr: expr) => {
        let result = $result_expr;
        if result != ffi::clfftStatus::CLFFT_SUCCESS {
            let error_code: i32 = unsafe { mem::transmute(result) };
            return ocl::Error::err(format!("FOREIGN_CLFFT_ERROR {}\nSee http://clmathlibraries.github.io/clFFT/clFFT_8h.html#a74e303bed132064cfa22c1cce96d2bce for further information", error_code));
        }
    }
}

macro_rules! clfft_panic {
    ( $result_expr: expr) => {
        let result = $result_expr;
        if result != ffi::clfftStatus::CLFFT_SUCCESS {
            panic!("Unexpeced error in foreign library: {:?}", result);
        }
    }
}

fn translate_to_fft_dim(dims: ocl::SpatialDims) -> ffi::clfftDim {
    match dims.dim_count() {
        1 => ffi::clfftDim::CLFFT_1D,
        2 => ffi::clfftDim::CLFFT_2D,
        3 => ffi::clfftDim::CLFFT_3D,
        n => panic!("Number of dimensions must be 1, 2 or 3, but it is {}", n)
    }
}

pub struct FftPlan {
    handle: ffi::clfftPlanHandle
}

impl FftPlan {
    /// Create a plan object initialized entirely with default values.
    ///
    /// A plan is a repository of state for calculating FFT's.  Allows the runtime to pre-calculate kernels, programs
    /// and buffers and associate them with buffers of specified dimensions.
    pub fn default<D: Into<ocl::SpatialDims>>(pro_que: &ocl::ProQue, dims: D)
        -> ocl::Result<FftPlan> {
        let context = unsafe { pro_que.context().core_as_ref().as_ptr() };
        let dims = dims.into();
        let dim = translate_to_fft_dim(dims);
        let lengths = try!(dims.to_lens());
        let mut plan: ffi::clfftPlanHandle = 0;
        clfft_try!( unsafe { ffi::clfftCreateDefaultPlan(&mut plan, context, dim, &lengths as *const usize) } );
        Ok(FftPlan {  handle: plan })
    }

    /// Returns the native clFFT plan handle.
    pub fn plan_handle(&self) -> ffi::clfftPlanHandle {
        self.handle
    }
}

/// Initialize the internal FFT resources such as FFT implementation caches kernels, programs, and buffers.
pub fn init_lib() -> ffi::clfftSetupData {
    let mut major: ocl::ffi::cl_uint = 0;
    let mut minor: ocl::ffi::cl_uint = 0;
    let mut patch: ocl::ffi::cl_uint = 0;
    clfft_panic!( unsafe { ffi::clfftGetVersion(&mut major, &mut minor, &mut patch) } );
    let data = ffi::clfftSetupData {
        major: major,
        minor: minor,
        patch: patch,
        debugFlags: 0,
    };

    clfft_panic!(unsafe { ffi::clfftSetup(&data) });
    data
}

/// Release all internal resources acquired during `init_lib`.
pub fn drop_lib() {
    unsafe { ffi::clfftTeardown() };
}

#[cfg(test)]
mod tests {
    use super::*;
    use ocl::{ProQue};
    use ocl::builders::ProgramBuilder;

    #[test]
    pub fn fft_test() {
        init_lib();
        let prog_bldr = ProgramBuilder::new();
        let ocl_pq = ProQue::builder()
            .prog_bldr(prog_bldr)
            .build()
            .expect("Building ProQue");
        FftPlan::default(&ocl_pq, [1000]);
        drop_lib();
    }
}<|endoftext|>


<commit_before>use std::cmp::min;
use std::fmt;
use std::io;
use std::str;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

use bytes::{Bytes, BytesMut};
use bytes::{IntoBuf, Buf, BufMut, BigEndian};
use tokio_io::codec::{Encoder, Decoder};
use tokio_proto::streaming::multiplex::{Frame, RequestId};

use constants::*;
use packet::{PacketMagic, PTYPES};

pub struct PacketHeader {
    pub magic: PacketMagic,
    pub ptype: u32,
    pub psize: u32,
}

impl fmt::Debug for PacketHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "PacketHeader {{ magic: {:?}, ptype: {}, size: {} }}",
               match self.magic {
                   PacketMagic::REQ => "REQ",
                   PacketMagic::RES => "RES",
                   PacketMagic::TEXT => "TEXT",
                   _ => "UNKNOWN",
               },
               match self.ptype {
                   p @ 0...42 => PTYPES[p as usize].name,
                   _ => "__UNIMPLEMENTED__",
               },
               self.psize)
    }
}

pub struct PacketCodec {
    data_todo: Option<usize>,
    request_counter: Arc<AtomicUsize>,
    active_request_id: RequestId,
}

impl PacketCodec {
    pub fn new(request_counter: Arc<AtomicUsize>) -> PacketCodec {
        PacketCodec {
            data_todo: None,
            request_counter: request_counter,
            active_request_id: 0,
        }
    }
}

pub type PacketItem = Frame<PacketHeader, Bytes, io::Error>;

impl PacketHeader {
    pub fn admin_decode(buf: &mut BytesMut) -> Result<Option<PacketItem>, io::Error> {
        let newline = buf[..].iter().position(|b| *b == b'\n');
        if let Some(n) = newline {
            let line = buf.split_to(n);
            buf.split_to(1); // drop the newline itself
            let data_str = match str::from_utf8(&line[..]) {
                Ok(s) => s,
                Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "invalid string")),
            };
            info!("admin command data: {:?}", data_str);
            let command = match data_str.trim() {
                "version" => ADMIN_VERSION,
                "status" => ADMIN_STATUS,
                _ => ADMIN_UNKNOWN,
            };
            return Ok(Some(Frame::Message {
                id: 0,
                message: PacketHeader {
                    magic: PacketMagic::TEXT,
                    ptype: command,
                    psize: 0,
                },
                body: false,
                solo: false,
            }));
        }
        Ok(None) // Wait for more data
    }

    pub fn decode(buf: &mut BytesMut,
                  request_counter: &Arc<AtomicUsize>)
                  -> Result<Option<PacketItem>, io::Error> {
        debug!("Decoding {:?}", buf);
        // Peek at first 4
        // Is this a req/res
        if buf.len() < 4 {
            return Ok(None);
        }
        let mut magic_buf: [u8; 4] = [0; 4];
        magic_buf.clone_from_slice(&buf[0..4]);
        let magic = match magic_buf {
            REQ => PacketMagic::REQ,
            RES => PacketMagic::RES,
            // TEXT/ADMIN protocol
            _ => PacketMagic::TEXT,
        };
        debug!("Magic is {:?}", magic);
        if magic == PacketMagic::TEXT {
            debug!("admin protocol detected");
            return PacketHeader::admin_decode(buf);
        }
        if buf.len() < 12 {
            return Ok(None);
        }
        buf.split_to(4);
        // Now get the type
        let ptype = buf.split_to(4).into_buf().get_u32::<BigEndian>();
        debug!("We got a {}", &PTYPES[ptype as usize].name);
        // Now the length
        let psize = buf.split_to(4).into_buf().get_u32::<BigEndian>();
        debug!("Data section is {} bytes", psize);
        let solo = match ptype {
            SUBMIT_JOB |
            SUBMIT_JOB_LOW |
            SUBMIT_JOB_HIGH |
            SUBMIT_REDUCE_JOB => false,
            GRAB_JOB | GRAB_JOB_UNIQ | GRAB_JOB_ALL => false,
            GET_STATUS |
            GET_STATUS_UNIQUE => false,
            _ => false,  // TODO: when we figure out how to Service::call on these, set to true
        };
        let req_id: RequestId = if solo {
            0
        } else {
            request_counter.fetch_add(1, Ordering::Relaxed) as RequestId
        };
        debug!("{} left in buf: {:?}", buf.len(), buf);
        Ok(Some(Frame::Message {
            id: req_id,
            message: PacketHeader {
                magic: magic,
                ptype: ptype,
                psize: psize,
            },
            body: true, // TODO: false for 0 psize?
            solo: solo,
        }))
    }

    pub fn to_bytes(&self) -> Bytes {
        let magic = match self.magic {
            PacketMagic::UNKNOWN => panic!("Unknown packet magic cannot be sent"),
            PacketMagic::REQ => REQ,
            PacketMagic::RES => RES,
            PacketMagic::TEXT => {
                return Bytes::from_static(b"");
            }
        };
        let mut buf = BytesMut::with_capacity(12);
        buf.extend(magic.iter());
        buf.put_u32::<BigEndian>(self.ptype);
        buf.put_u32::<BigEndian>(self.psize);
        buf.freeze()
    }

    pub fn new_text_res(body: &Bytes) -> PacketHeader {
        PacketHeader {
            magic: PacketMagic::TEXT,
            ptype: ADMIN_RESPONSE,
            psize: body.len() as u32,
        }
    }
}

impl Decoder for PacketCodec {
    type Item = Frame<PacketHeader, Bytes, io::Error>;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
        match self.data_todo {
            None => {
                match PacketHeader::decode(buf, &self.request_counter)? {
                    Some(Frame::Message { id, message, body, solo }) => {
                        self.active_request_id = id;
                        self.data_todo = Some(message.psize as usize);
                        Ok(Some(Frame::Message {
                            id: id,
                            message: message,
                            body: body,
                            solo: solo,
                        }))
                    }
                    Some(_) => panic!("Expecting Frame::Message, got something else"),
                    None => Ok(None),
                }
            }
            Some(0) => {
                self.data_todo = None;
                Ok(Some(Frame::Body {
                    id: self.active_request_id,
                    chunk: None,
                }))
            }
            Some(data_todo) => {
                let chunk_size = min(buf.len(), data_todo);
                if chunk_size == 0 {
                    debug!("0 length chunk? buf.len() = {} data_todo = {}", buf.len(), data_todo);
                    Ok(None)
                } else {
                    trace!("chunk of length {} from buf of {:?}", chunk_size, buf);
                    self.data_todo = Some(data_todo - chunk_size);
                    Ok(Some(Frame::Body {
                        id: self.active_request_id,
                        chunk: Some(buf.split_to(chunk_size).freeze()),
                    }))
                }
            }
        }
    }
}

impl Encoder for PacketCodec {
    type Item = Frame<PacketHeader, Bytes, io::Error>;
    type Error = io::Error;

    fn encode(&mut self, msg: Self::Item, buf: &mut BytesMut) -> io::Result<()> {
        debug!("Encoding {:?}", msg);
        match msg {
            Frame::Message { id, message, body, solo } => {
                trace!("Encoding header for id={} solo={}", id, solo);
                if body {
                    debug!("body follows")
                }
                buf.extend(message.to_bytes())
            }
            Frame::Body { id, chunk } => {
                trace!("Encoding body for id={}", id);
                match chunk {
                    Some(chunk) => buf.extend_from_slice(&chunk[..]),
                    None => {}
                }
            }
            Frame::Error { id, error } => {
                error!("Sending error frame for id={}. {}", id, error);
                buf.extend("ERR UNKNOWN_COMMAND Unknown+server+command".bytes())
            }
        }
        Ok(())
    }
}
<commit_msg>cargo fmt<commit_after>use std::cmp::min;
use std::fmt;
use std::io;
use std::str;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

use bytes::{Bytes, BytesMut};
use bytes::{IntoBuf, Buf, BufMut, BigEndian};
use tokio_io::codec::{Encoder, Decoder};
use tokio_proto::streaming::multiplex::{Frame, RequestId};

use constants::*;
use packet::{PacketMagic, PTYPES};

pub struct PacketHeader {
    pub magic: PacketMagic,
    pub ptype: u32,
    pub psize: u32,
}

impl fmt::Debug for PacketHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "PacketHeader {{ magic: {:?}, ptype: {}, size: {} }}",
               match self.magic {
                   PacketMagic::REQ => "REQ",
                   PacketMagic::RES => "RES",
                   PacketMagic::TEXT => "TEXT",
                   _ => "UNKNOWN",
               },
               match self.ptype {
                   p @ 0...42 => PTYPES[p as usize].name,
                   _ => "__UNIMPLEMENTED__",
               },
               self.psize)
    }
}

pub struct PacketCodec {
    data_todo: Option<usize>,
    request_counter: Arc<AtomicUsize>,
    active_request_id: RequestId,
}

impl PacketCodec {
    pub fn new(request_counter: Arc<AtomicUsize>) -> PacketCodec {
        PacketCodec {
            data_todo: None,
            request_counter: request_counter,
            active_request_id: 0,
        }
    }
}

pub type PacketItem = Frame<PacketHeader, Bytes, io::Error>;

impl PacketHeader {
    pub fn admin_decode(buf: &mut BytesMut) -> Result<Option<PacketItem>, io::Error> {
        let newline = buf[..].iter().position(|b| *b == b'\n');
        if let Some(n) = newline {
            let line = buf.split_to(n);
            buf.split_to(1); // drop the newline itself
            let data_str = match str::from_utf8(&line[..]) {
                Ok(s) => s,
                Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "invalid string")),
            };
            info!("admin command data: {:?}", data_str);
            let command = match data_str.trim() {
                "version" => ADMIN_VERSION,
                "status" => ADMIN_STATUS,
                _ => ADMIN_UNKNOWN,
            };
            return Ok(Some(Frame::Message {
                id: 0,
                message: PacketHeader {
                    magic: PacketMagic::TEXT,
                    ptype: command,
                    psize: 0,
                },
                body: false,
                solo: false,
            }));
        }
        Ok(None) // Wait for more data
    }

    pub fn decode(buf: &mut BytesMut,
                  request_counter: &Arc<AtomicUsize>)
                  -> Result<Option<PacketItem>, io::Error> {
        debug!("Decoding {:?}", buf);
        // Peek at first 4
        // Is this a req/res
        if buf.len() < 4 {
            return Ok(None);
        }
        let mut magic_buf: [u8; 4] = [0; 4];
        magic_buf.clone_from_slice(&buf[0..4]);
        let magic = match magic_buf {
            REQ => PacketMagic::REQ,
            RES => PacketMagic::RES,
            // TEXT/ADMIN protocol
            _ => PacketMagic::TEXT,
        };
        debug!("Magic is {:?}", magic);
        if magic == PacketMagic::TEXT {
            debug!("admin protocol detected");
            return PacketHeader::admin_decode(buf);
        }
        if buf.len() < 12 {
            return Ok(None);
        }
        buf.split_to(4);
        // Now get the type
        let ptype = buf.split_to(4).into_buf().get_u32::<BigEndian>();
        debug!("We got a {}", &PTYPES[ptype as usize].name);
        // Now the length
        let psize = buf.split_to(4).into_buf().get_u32::<BigEndian>();
        debug!("Data section is {} bytes", psize);
        let solo = match ptype {
            SUBMIT_JOB |
            SUBMIT_JOB_LOW |
            SUBMIT_JOB_HIGH |
            SUBMIT_REDUCE_JOB => false,
            GRAB_JOB | GRAB_JOB_UNIQ | GRAB_JOB_ALL => false,
            GET_STATUS |
            GET_STATUS_UNIQUE => false,
            _ => false,  // TODO: when we figure out how to Service::call on these, set to true
        };
        let req_id: RequestId = if solo {
            0
        } else {
            request_counter.fetch_add(1, Ordering::Relaxed) as RequestId
        };
        debug!("{} left in buf: {:?}", buf.len(), buf);
        Ok(Some(Frame::Message {
            id: req_id,
            message: PacketHeader {
                magic: magic,
                ptype: ptype,
                psize: psize,
            },
            body: true, // TODO: false for 0 psize?
            solo: solo,
        }))
    }

    pub fn to_bytes(&self) -> Bytes {
        let magic = match self.magic {
            PacketMagic::UNKNOWN => panic!("Unknown packet magic cannot be sent"),
            PacketMagic::REQ => REQ,
            PacketMagic::RES => RES,
            PacketMagic::TEXT => {
                return Bytes::from_static(b"");
            }
        };
        let mut buf = BytesMut::with_capacity(12);
        buf.extend(magic.iter());
        buf.put_u32::<BigEndian>(self.ptype);
        buf.put_u32::<BigEndian>(self.psize);
        buf.freeze()
    }

    pub fn new_text_res(body: &Bytes) -> PacketHeader {
        PacketHeader {
            magic: PacketMagic::TEXT,
            ptype: ADMIN_RESPONSE,
            psize: body.len() as u32,
        }
    }
}

impl Decoder for PacketCodec {
    type Item = Frame<PacketHeader, Bytes, io::Error>;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Self::Item>, io::Error> {
        match self.data_todo {
            None => {
                match PacketHeader::decode(buf, &self.request_counter)? {
                    Some(Frame::Message { id, message, body, solo }) => {
                        self.active_request_id = id;
                        self.data_todo = Some(message.psize as usize);
                        Ok(Some(Frame::Message {
                            id: id,
                            message: message,
                            body: body,
                            solo: solo,
                        }))
                    }
                    Some(_) => panic!("Expecting Frame::Message, got something else"),
                    None => Ok(None),
                }
            }
            Some(0) => {
                self.data_todo = None;
                Ok(Some(Frame::Body {
                    id: self.active_request_id,
                    chunk: None,
                }))
            }
            Some(data_todo) => {
                let chunk_size = min(buf.len(), data_todo);
                if chunk_size == 0 {
                    debug!("0 length chunk? buf.len() = {} data_todo = {}",
                           buf.len(),
                           data_todo);
                    Ok(None)
                } else {
                    trace!("chunk of length {} from buf of {:?}", chunk_size, buf);
                    self.data_todo = Some(data_todo - chunk_size);
                    Ok(Some(Frame::Body {
                        id: self.active_request_id,
                        chunk: Some(buf.split_to(chunk_size).freeze()),
                    }))
                }
            }
        }
    }
}

impl Encoder for PacketCodec {
    type Item = Frame<PacketHeader, Bytes, io::Error>;
    type Error = io::Error;

    fn encode(&mut self, msg: Self::Item, buf: &mut BytesMut) -> io::Result<()> {
        debug!("Encoding {:?}", msg);
        match msg {
            Frame::Message { id, message, body, solo } => {
                trace!("Encoding header for id={} solo={}", id, solo);
                if body {
                    debug!("body follows")
                }
                buf.extend(message.to_bytes())
            }
            Frame::Body { id, chunk } => {
                trace!("Encoding body for id={}", id);
                match chunk {
                    Some(chunk) => buf.extend_from_slice(&chunk[..]),
                    None => {}
                }
            }
            Frame::Error { id, error } => {
                error!("Sending error frame for id={}. {}", id, error);
                buf.extend("ERR UNKNOWN_COMMAND Unknown+server+command".bytes())
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use ::LEVEL_WIDTH;
use ::LEVEL_HEIGHT;

struct Coordinate {
    x: u64,
    y: u64,
}

impl Coordinate {
    fn new(x: u64, y: u64) -> Self {
        Coordinate { x: x, y: y }
    }
    fn origin() -> Self {
        Coordinate::new(0, 0);
    }

    fn clone_coord(&self) -> Self{
        Coordinate{
            x: self.x,
            y: self.y,
        }
    }
    fn move_coord(&mut self, dx: u64, dy: u64) {
        let new_x = self.x + dx;
        let new_y = self.y + dy;
        self.x = if new_x < 0 {
            0
        } else if new_x > LEVEL_WIDTH {
            LEVEL_WIDTH
        }
        else {
            new_x
        };
        self.y = if new_y < 0 {
            0
        } else if new_y > LEVEL_WIDTH {
            LEVEL_WIDTH
        }
        else {
            new_y
        }
    }
}
<commit_msg>resolve errors<commit_after>use ::LEVEL_WIDTH;
use ::LEVEL_HEIGHT;

pub struct Coordinate {
    x: u64,
    y: u64,
}

impl Coordinate {
    pub fn new(x: u64, y: u64) -> Self {
        Coordinate { x: x, y: y }
    }
    pub fn origin() -> Self {
        Coordinate::new(0, 0)
    }

    pub fn clone_coord(&self) -> Self{
        Coordinate{
            x: self.x,
            y: self.y,
        }
    }
    pub fn move_coord(&mut self, dx: u64, dy: u64) {
        let new_x = self.x + dx;
        let new_y = self.y + dy;
        self.x = if new_x < 0 {
            0
        } else if new_x > LEVEL_WIDTH {
            LEVEL_WIDTH
        }
        else {
            new_x
        };
        self.y = if new_y < 0 {
            0
        } else if new_y > LEVEL_WIDTH {
            LEVEL_WIDTH
        }
        else {
            new_y
        }
    }
}
<|endoftext|>


<commit_before>
use std::fmt;

pub struct Flat2dArray<T: Default + Copy> {
  data: Vec<T>,
  width: usize,
  height: usize
}

impl<T: Default + Copy> Flat2dArray<T> {
  pub fn new(width: usize, height: usize) -> Flat2dArray<T> {
    Flat2dArray {
      data: vec![T::default(); width * height],
      width: width,
      height: height
    }
  }

  pub fn is_out_of_bounds(&self, x: usize, y: usize) -> bool {
    x >= self.width || y >= self.height
  }

  fn assert_not_out_of_bounds(&self, x: usize, y: usize) {
    if self.is_out_of_bounds(x, y) {
      panic!(format!("Out of bounds: {}, {}", x, y));
    }
  }

  fn get_index(&self, x: usize, y: usize) -> usize {
    self.assert_not_out_of_bounds(x, y);
    x + y * self.width
  }

  pub fn get(&self, x: usize, y: usize) -> T {
    let index = self.get_index(x, y);

    self.data[index]
  }

  pub fn set(&mut self, x: usize, y: usize, val: T) {
    let index = self.get_index(x, y);

    self.data[index] = val;
  }

  pub fn get_width(&self) -> usize {
    self.width
  }

  pub fn get_height(&self) -> usize {
    self.height
  }
}

impl<T> fmt::Display for Flat2dArray<T>
  where T: Default + Copy + fmt::Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      writeln!(f, "width: {} height: {}", self.width, self.height);

      for y in 0 .. self.height {
        for x in 0 .. self.width {
          write!(f, "{: >3} ", self.get(x, y));
        }
        writeln!(f, "");
      }
      Ok(())
    }
}

pub fn construct_regular_matrix(width: usize, height: usize) -> Flat2dArray<usize> {
  let mut array: Flat2dArray<usize> = Flat2dArray::new(width, height);

  for y in 0..height {
    for x in 0..width {
      array.set(x, y, x + width * y);
    }
  }

  array
}

fn create_part_oblique<T>(array: &Flat2dArray<T>, start_x: usize, start_y: usize) -> Vec<T>
where T: Default + Copy {

  let mut x = start_x;
  let mut y = start_y;

  let mut part_result: Vec<T> = Vec::new();

  while !array.is_out_of_bounds(x, y) {
    part_result.push(array.get(x, y));

    if x == 0 {
      break;
    }

    x = x - 1;
    y = y + 1;
  }

  part_result
}

pub fn oblique<T>(array: &Flat2dArray<T>) -> Vec<Vec<T>>
where T: Default + Copy {
  let mut result: Vec<Vec<T>> = Vec::new();

  for start_x in 0..array.get_width() {
    let part_result = create_part_oblique(array, start_x, 0);
    result.push( part_result );
  }

  for start_y in 1..array.get_height() {
    let part_result = create_part_oblique(array, array.get_width() - 1, start_y);
    result.push( part_result );
  }

  result
}

#[cfg(test)]
mod tests {
  use std::fmt;
  use dp256::*;

  fn print_obliqued_vec<T: fmt::Display>(vv: &Vec<Vec<T>>) {
    println!("");
    for v in vv {
      for value in v {
        print!("{: >3}", value);
      }
      println!("");
    }
  }

  #[test]
  fn test_create() {
    let a2d: Flat2dArray<i32> = Flat2dArray::new( 5, 10 );

    assert_eq!( 5, a2d.get_width() );
    assert_eq!( 10, a2d.get_height() );
  }

  #[test]
  #[should_panic]
  fn test_out_of_bounds() {
    let a2d: Flat2dArray<i32> = Flat2dArray::new(5, 10);

    a2d.get(6, 5);
  }

  #[test]
  fn test_regular_matrix() {
    let a2d = construct_regular_matrix(10, 5);

    for x in 0 .. a2d.get_width() {
      for y in 0 .. a2d.get_height() {
        assert_eq!( x + y * a2d.get_width(), a2d.get(x, y) );
      }
    }

    println!("{}", a2d);
  }

  #[test]
  fn test_oblique() {
    let array = construct_regular_matrix(6, 6);

    let vec = oblique(&array);

    print_obliqued_vec(&vec);
  }

}
<commit_msg>updated dp256<commit_after>
use std::fmt;

pub struct Flat2dArray<T: Copy> {
  data: Vec<T>,
  width: usize,
  height: usize
}

impl<T: Default + Copy> Flat2dArray<T> {
  pub fn new_default(width: usize, height: usize) -> Flat2dArray<T> {
    Flat2dArray {
      data: vec![T::default(); width * height],
      width: width,
      height: height
    }
  }
}

impl<T: Copy> Flat2dArray<T> {
  pub fn new(width: usize, height: usize, value: T) -> Flat2dArray<T> {
    Flat2dArray {
      data: vec![value; width * height],
      width: width,
      height: height
    }
  }

  pub fn new_zero_sized() -> Flat2dArray<T> {
    Flat2dArray {
      data: Vec::new(),
      width: 0,
      height: 0
    }
  }

  pub fn is_out_of_bounds(&self, x: usize, y: usize) -> bool {
    x >= self.width || y >= self.height
  }

  fn assert_not_out_of_bounds(&self, x: usize, y: usize) {
    if self.is_out_of_bounds(x, y) {
      panic!(format!("Out of bounds: {}, {}", x, y));
    }
  }

  fn get_index(&self, x: usize, y: usize) -> usize {
    self.assert_not_out_of_bounds(x, y);
    x + y * self.width
  }

  pub fn get(&self, x: usize, y: usize) -> T {
    let index = self.get_index(x, y);

    self.data[index]
  }

  pub fn set(&mut self, x: usize, y: usize, val: T) {
    let index = self.get_index(x, y);

    self.data[index] = val;
  }

  pub fn get_width(&self) -> usize {
    self.width
  }

  pub fn get_height(&self) -> usize {
    self.height
  }
}

impl<T> From<Vec<Vec<T>>> for Flat2dArray<T>
where T: Copy {
  fn from(vec: Vec<Vec<T>>) -> Flat2dArray<T> {
    let height = vec.len();

    if height == 0 {
      return Flat2dArray::new_zero_sized();
    }

    assert!(height > 0);

    let first_width = vec[0].len();

    if first_width == 0 {
      return Flat2dArray::new_zero_sized();
    }

    assert!(first_width > 0);

    let mut result = Flat2dArray::new( first_width, height, vec[0][0] );

    for y in 0..height {
      let width = vec[y].len();
      assert_eq!(first_width, width);

      for x in 0..width {
        result.set(x, y, vec[y][x]);
      }
    }

    result
  }
}

impl<T> fmt::Display for Flat2dArray<T>
  where T: Default + Copy + fmt::Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      writeln!(f, "width: {} height: {}", self.width, self.height);

      for y in 0 .. self.height {
        for x in 0 .. self.width {
          write!(f, "{: >3} ", self.get(x, y));
        }
        writeln!(f, "");
      }
      Ok(())
    }
}

pub fn construct_regular_matrix(width: usize, height: usize) -> Flat2dArray<usize> {
  let mut array: Flat2dArray<usize> = Flat2dArray::new_default(width, height);

  for y in 0..height {
    for x in 0..width {
      array.set(x, y, x + width * y);
    }
  }

  array
}

fn create_part_oblique<T>(array: &Flat2dArray<T>, start_x: usize, start_y: usize) -> Vec<T>
where T: Copy {

  let mut x = start_x;
  let mut y = start_y;

  let mut part_result: Vec<T> = Vec::new();

  while !array.is_out_of_bounds(x, y) {
    part_result.push(array.get(x, y));

    if x == 0 {
      break;
    }

    x = x - 1;
    y = y + 1;
  }

  part_result
}

pub fn oblique<T>(array: &Flat2dArray<T>) -> Vec<Vec<T>>
where T: Default + Copy {
  let mut result: Vec<Vec<T>> = Vec::new();

  for start_x in 0..array.get_width() {
    let part_result = create_part_oblique(array, start_x, 0);
    result.push( part_result );
  }

  for start_y in 1..array.get_height() {
    let part_result = create_part_oblique(array, array.get_width() - 1, start_y);
    result.push( part_result );
  }

  result
}

pub fn de_oblique_square<T>(vec: &Vec<Vec<T>>) -> Flat2dArray<T>
where T: Copy {
  unimplemented!();
}

#[cfg(test)]
mod tests {
  use std::fmt;
  use dp256::*;

  fn print_obliqued_vec<T: fmt::Display>(vv: &Vec<Vec<T>>) {
    println!("");
    for v in vv {
      for value in v {
        print!("{: >3}", value);
      }
      println!("");
    }
  }

  #[test]
  fn test_create() {
    let a2d: Flat2dArray<i32> = Flat2dArray::new_default( 5, 10 );

    assert_eq!( 5, a2d.get_width() );
    assert_eq!( 10, a2d.get_height() );
  }

  #[test]
  #[should_panic]
  fn test_out_of_bounds() {
    let a2d: Flat2dArray<i32> = Flat2dArray::new_default(5, 10);

    a2d.get(6, 5);
  }

  #[test]
  fn test_regular_matrix() {
    let a2d = construct_regular_matrix(10, 5);

    for x in 0 .. a2d.get_width() {
      for y in 0 .. a2d.get_height() {
        assert_eq!( x + y * a2d.get_width(), a2d.get(x, y) );
      }
    }

    println!("{}", a2d);
  }

  #[test]
  fn test_oblique() {
    let array = construct_regular_matrix(6, 6);

    let vec = oblique(&array);

    print_obliqued_vec(&vec);
  }

  #[test]
  fn test_from_vec() {
    let mut vec: Vec<Vec<usize>> = Vec::new();
    for y in 0..6 {
      let mut part_vec: Vec<usize> = Vec::new();
      for x in 0..7 {
        part_vec.push(x * y);
      }
      vec.push(part_vec);
    }

    let vec_copy: Vec<Vec<usize>> = vec.to_vec();

    let array = Flat2dArray::from(vec);

    assert_eq!(6, array.get_height());
    assert_eq!(7, array.get_width());

    for y in 0..6 {
      for x in 0..7 {
        assert_eq!(vec_copy[y][x], array.get(x, y));
      }
    }
  }

}
<|endoftext|>


<commit_before>use std::rc::Rc;
use digit_slice::DigitSlice;

pub enum Shape<'a, N: 'a + Noun> {
    // A natural number represented as a little-endian sequence of 8-bit
    // digits.
    Atom(&'a [u8]),
    // An ordered pair of nouns.
    Cell(&'a N, &'a N),
}

/// A Nock noun, the basic unit of representation.
///
/// A noun is an atom or a cell. An atom is any natural number. A cell is any
/// ordered pair of nouns.
pub trait Noun: Sized+Clone {
    fn get<'a>(&'a self) -> Shape<'a, Self>;

    /// Memory address or other unique identifier for the noun.
    fn addr(&self) -> usize;

    /// Run a memoizing fold over the noun
    fn fold<'a, F, G, T: Clone>(&'a self, leaf: &mut F, branch: &mut G) -> T
        where F: FnMut(&[u8]) -> T,
              G: FnMut(&T, &T) -> T
    {
        /*
        use std::collections::HashMap;
        fn g<'a, F, T: Clone>(noun: &'a Self, memo: &mut HashMap<usize, T>, leaf: &mut F, branch: &mut G) -> T
            where F: FnMut(&[u8]) -> T,
                  G: FnMut(&T, &T) -> T
        {
            let key = noun.addr();
            if memo.contains_key(&key) {
                memo.get(&key).unwrap().clone()
            } else {
                let ret = h(noun, memo, f);
                memo.insert(key, ret.clone());
                ret
            }
        }

        fn h<'a, F, T: Clone>(noun: &'a Noun, memo: &mut HashMap<usize, T>, f: &mut F) -> T
            where F: FnMut(FoldState<'a, T>) -> T
        {
            match noun {
                &Atom(ref a) => f(FoldState::Atom(*a)),
                &BigAtom(ref a) => f(FoldState::BigAtom(a)),
                &Cell(ref p, ref q) => {
                    let p = g(p, memo, f);
                    let q = g(q, memo, f);
                    f(FoldState::Cell(p, q))
                }
            }
        }

        h(self, &mut HashMap::new(), &mut f)
        */
        match self.get() {
            Shape::Atom(x) => leaf(x),
            Shape::Cell(ref a, ref b) => {
                let a = a.fold(leaf, branch);
                let b = b.fold(leaf, branch);
                branch(&a, &b)
            }
        }
    }
}

pub trait Context: Sized {
    type Noun: Noun;

    /// Build a new atom noun from a little-endian 8-bit digit sequence.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun;

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun;

    fn noun<T: ToNoun>(&mut self, item: T) -> Self::Noun {
        item.to_noun(self)
    }
}

/// Trait for types that can convert themselves to a noun.
pub trait ToNoun {
    fn to_noun<C: Context>(self, &mut C) -> C::Noun;
}

impl<T> ToNoun for T where T: DigitSlice
{
    fn to_noun<C: Context>(self, ctx: &mut C) -> C::Noun {
        ctx.atom(self.as_digits())
    }
}

#[derive(Clone, PartialEq, Eq)]
enum HeapNounInner {
    Atom(Vec<u8>),
    Cell(Rc<HeapNoun>, Rc<HeapNoun>),
}

#[derive(Clone, PartialEq, Eq)]
pub struct HeapNoun(HeapNounInner);

impl Noun for HeapNoun {
    fn get<'a>(&'a self) -> Shape<'a, Self> {
        match self.0 {
            HeapNounInner::Atom(ref v) => Shape::Atom(&v),
            HeapNounInner::Cell(ref a, ref b) => Shape::Cell(&*a, &*b),
        }
    }

    fn addr(&self) -> usize {
        &*self as *const _ as usize
    }
}

#[derive(Default)]
pub struct Heap;

impl Context for Heap {
    type Noun = HeapNoun;

    /// Build a new atom noun.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun {
        HeapNoun(HeapNounInner::Atom(digits.to_vec()))
    }

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun {
        HeapNoun(HeapNounInner::Cell(Rc::new(a), Rc::new(b)))
    }
}

#[cfg(test)]
mod tests {
    use super::{Context, Heap};

    #[test]
    fn scratch() {
        let x = Heap.noun(123u32);
        assert!(x == Heap.noun(123u8));
    }
}
<commit_msg>Fold for new Noun<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::hash;
use digit_slice::DigitSlice;

pub enum Shape<'a, N: 'a + Noun> {
    // A natural number represented as a little-endian sequence of 8-bit
    // digits.
    Atom(&'a [u8]),
    // An ordered pair of nouns.
    Cell(&'a N, &'a N),
}

/// A Nock noun, the basic unit of representation.
///
/// A noun is an atom or a cell. An atom is any natural number. A cell is any
/// ordered pair of nouns.
pub trait Noun: Sized+Clone {
    fn get<'a>(&'a self) -> Shape<'a, Self>;

    /// Memory address or other unique identifier for the noun.
    fn addr(&self) -> usize;

    /// Run a memoizing fold over the noun
    fn fold<'a, F, G, T: Clone>(&'a self, mut leaf: F, mut branch: G) -> T
        where F: FnMut(&[u8]) -> T,
              G: FnMut(&T, &T) -> T
    {
        fn h<'a, S, F, G, T>(noun: &'a S,
                             memo: &mut HashMap<usize, T>,
                             leaf: &mut F,
                             branch: &mut G)
                             -> T
            where S: Noun,
                  F: FnMut(&[u8]) -> T,
                  G: FnMut(&T, &T) -> T,
                  T: Clone
        {
            let key = noun.addr();

            if memo.contains_key(&key) {
                memo.get(&key).unwrap().clone()
            } else {
                let ret = match noun.get() {
                    Shape::Atom(x) => leaf(x),
                    Shape::Cell(ref a, ref b) => {
                        let a = h(*a, memo, leaf, branch);
                        let b = h(*b, memo, leaf, branch);
                        branch(&a, &b)
                    }
                };
                memo.insert(key, ret.clone());
                ret
            }
        }

        h(self, &mut HashMap::new(), &mut leaf, &mut branch)
    }
}

pub trait Context: Sized {
    type Noun: Noun;

    /// Build a new atom noun from a little-endian 8-bit digit sequence.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun;

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun;

    fn noun<T: ToNoun>(&mut self, item: T) -> Self::Noun {
        item.to_noun(self)
    }
}

/// Trait for types that can convert themselves to a noun.
pub trait ToNoun {
    fn to_noun<C: Context>(self, &mut C) -> C::Noun;
}

impl<T> ToNoun for T where T: DigitSlice
{
    fn to_noun<C: Context>(self, ctx: &mut C) -> C::Noun {
        ctx.atom(self.as_digits())
    }
}

#[derive(Clone, PartialEq, Eq)]
enum HeapNounInner {
    Atom(Vec<u8>),
    Cell(Rc<HeapNoun>, Rc<HeapNoun>),
}

#[derive(Clone, PartialEq, Eq)]
pub struct HeapNoun(HeapNounInner);

impl Noun for HeapNoun {
    fn get<'a>(&'a self) -> Shape<'a, Self> {
        match self.0 {
            HeapNounInner::Atom(ref v) => Shape::Atom(&v),
            HeapNounInner::Cell(ref a, ref b) => Shape::Cell(&*a, &*b),
        }
    }

    fn addr(&self) -> usize {
        &*self as *const _ as usize
    }
}

#[derive(Default)]
pub struct Heap;

impl Context for Heap {
    type Noun = HeapNoun;

    /// Build a new atom noun.
    fn atom(&mut self, digits: &[u8]) -> Self::Noun {
        HeapNoun(HeapNounInner::Atom(digits.to_vec()))
    }

    /// Build a new cell noun from two existing nouns.
    fn cell(&mut self, a: Self::Noun, b: Self::Noun) -> Self::Noun {
        HeapNoun(HeapNounInner::Cell(Rc::new(a), Rc::new(b)))
    }
}

#[cfg(test)]
mod tests {
    use super::{Context, Heap};

    #[test]
    fn scratch() {
        let x = Heap.noun(123u32);
        assert!(x == Heap.noun(123u8));
    }
}
<|endoftext|>


<commit_before>// Rust JSON-RPC Library
// Written in 2015 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Error handling
//!
//! Some useful methods for creating Error objects
//!

use hyper;
use json;
use json::value::Value as JsonValue;
use serde;

use Response;

/// A library error
#[derive(Debug)]
pub enum Error {
    /// Json error
    Json(json::error::Error),
    /// Client HTTP status error
    BadStatus(hyper::status::StatusCode),
    /// Client error
    Hyper(hyper::error::Error),
    /// Error response
    Rpc(RpcError),
    /// Response has neither error nor result
    NoErrorOrResult
}

/// Standard error responses, as described at at
/// http://www.jsonrpc.org/specification#error_object
///
/// # Documentation Copyright
/// Copyright (C) 2007-2010 by the JSON-RPC Working Group
///
/// This document and translations of it may be used to implement JSON-RPC, it
/// may be copied and furnished to others, and derivative works that comment
/// on or otherwise explain it or assist in its implementation may be prepared,
/// copied, published and distributed, in whole or in part, without restriction
/// of any kind, provided that the above copyright notice and this paragraph
/// are included on all such copies and derivative works. However, this document
/// itself may not be modified in any way.
///
/// The limited permissions granted above are perpetual and will not be revoked.
///
/// This document and the information contained herein is provided "AS IS" and
/// ALL WARRANTIES, EXPRESS OR IMPLIED are DISCLAIMED, INCLUDING BUT NOT LIMITED
/// TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY
/// RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
/// PARTICULAR PURPOSE.
///
pub enum StandardError {
    /// Invalid JSON was received by the server.
    /// An error occurred on the server while parsing the JSON text.
    ParseError,
    /// The JSON sent is not a valid Request object.
    InvalidRequest,
    /// The method does not exist / is not available.
    MethodNotFound,
    /// Invalid method parameter(s).
    InvalidParams,
    /// Internal JSON-RPC error.
    InternalError
}

#[derive(Clone, Debug, PartialEq)]
/// A JSONRPC error object
pub struct RpcError {
    /// The integer identifier of the error
    pub code: i32,
    /// A string describing the error
    pub message: String,
    /// Additional data specific to the error
    pub data: Option<JsonValue>
}

/// Create a standard error responses
pub fn standard_error(code: StandardError, data: Option<JsonValue>) -> RpcError {
    match code {
        StandardError::ParseError => RpcError {
            code: -32700,
            message: "Parse error".to_string(),
            data: data
        },
        StandardError::InvalidRequest => RpcError {
            code: -32600,
            message: "Invalid Request".to_string(),
            data: data
        },
        StandardError::MethodNotFound => RpcError {
            code: -32601,
            message: "Method not found".to_string(),
            data: data
        },
        StandardError::InvalidParams => RpcError {
            code: -32602,
            message: "Invalid params".to_string(),
            data: data
        },
        StandardError::InternalError => RpcError {
            code: -32603,
            message: "Internal error".to_string(),
            data: data
        },
    }
}

/// Converts a Rust `Result` to a JSONRPC response object
pub fn result_to_response(result: Result<JsonValue, RpcError>, id: JsonValue) -> Response {
    match result {
        Ok(data) => Response { result: Some(data), error: None, id: id },
        Err(err) => Response { result: None, error: Some(err), id: id }
    }
}

serde_struct_impl!(
    RpcError,
    rpc_error_mod,
    code,
    message,
    data
);

#[cfg(test)]
mod tests {
    use super::StandardError::{ParseError, InvalidRequest, MethodNotFound, InvalidParams, InternalError};
    use super::{standard_error, result_to_response};

    use json::value::Value as JsonValue;

    #[test]
    fn test_parse_error() {
        let resp = result_to_response(Err(standard_error(ParseError, None)), JsonValue::U64(1));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::U64(1));
        assert_eq!(resp.error.unwrap().code, -32700);
    }

    #[test]
    fn test_invalid_request() {
        let resp = result_to_response(Err(standard_error(InvalidRequest, None)), JsonValue::I64(1));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::I64(1));
        assert_eq!(resp.error.unwrap().code, -32600);
    }

    #[test]
    fn test_method_not_found() {
        let resp = result_to_response(Err(standard_error(MethodNotFound, None)), JsonValue::U64(1));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::U64(1));
        assert_eq!(resp.error.unwrap().code, -32601);
    }

    #[test]
    fn test_invalid_params() {
        let resp = result_to_response(Err(standard_error(InvalidParams, None)), JsonValue::String("123".to_string()));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::String("123".to_string()));
        assert_eq!(resp.error.unwrap().code, -32602);
    }

    #[test]
    fn test_internal_error() {
        let resp = result_to_response(Err(standard_error(InternalError, None)), JsonValue::I64(-1));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::I64(-1));
        assert_eq!(resp.error.unwrap().code, -32603);
    }
}

<commit_msg>Implement Error for main error type<commit_after>// Rust JSON-RPC Library
// Written in 2015 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Error handling
//!
//! Some useful methods for creating Error objects
//!

use std::{error, fmt};

use hyper;
use json;
use json::value::Value as JsonValue;
use serde;

use Response;

/// A library error
#[derive(Debug)]
pub enum Error {
    /// Json error
    Json(json::error::Error),
    /// Client HTTP status error
    BadStatus(hyper::status::StatusCode),
    /// Client error
    Hyper(hyper::error::Error),
    /// Error response
    Rpc(RpcError),
    /// Response has neither error nor result
    NoErrorOrResult
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Json(ref e) => write!(f, "JSON decode error: {}", e),
            Error::BadStatus(s) => write!(f, "HTTP error {}", s),
            Error::Hyper(ref e) => write!(f, "Hyper error: {}", e),
            Error::Rpc(ref r) => write!(f, "RPC error response: {:?}", r),
            Error::NoErrorOrResult => f.write_str("RPC response had neither error nor result")
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Json(_) => "JSON decode error",
            Error::BadStatus(_) => "Bad HTTP status",
            Error::Hyper(_) => "Hyper error",
            Error::Rpc(_) => "RPC error response",
            Error::NoErrorOrResult => "Malformed RPC response",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Json(ref e) => Some(e),
            Error::BadStatus(_) => None,
            Error::Hyper(ref e) => Some(e),
            Error::Rpc(_) => None,
            Error::NoErrorOrResult => None
        }
    }
}

/// Standard error responses, as described at at
/// http://www.jsonrpc.org/specification#error_object
///
/// # Documentation Copyright
/// Copyright (C) 2007-2010 by the JSON-RPC Working Group
///
/// This document and translations of it may be used to implement JSON-RPC, it
/// may be copied and furnished to others, and derivative works that comment
/// on or otherwise explain it or assist in its implementation may be prepared,
/// copied, published and distributed, in whole or in part, without restriction
/// of any kind, provided that the above copyright notice and this paragraph
/// are included on all such copies and derivative works. However, this document
/// itself may not be modified in any way.
///
/// The limited permissions granted above are perpetual and will not be revoked.
///
/// This document and the information contained herein is provided "AS IS" and
/// ALL WARRANTIES, EXPRESS OR IMPLIED are DISCLAIMED, INCLUDING BUT NOT LIMITED
/// TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY
/// RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
/// PARTICULAR PURPOSE.
///
#[derive(Debug)]
pub enum StandardError {
    /// Invalid JSON was received by the server.
    /// An error occurred on the server while parsing the JSON text.
    ParseError,
    /// The JSON sent is not a valid Request object.
    InvalidRequest,
    /// The method does not exist / is not available.
    MethodNotFound,
    /// Invalid method parameter(s).
    InvalidParams,
    /// Internal JSON-RPC error.
    InternalError
}

#[derive(Clone, Debug, PartialEq)]
/// A JSONRPC error object
pub struct RpcError {
    /// The integer identifier of the error
    pub code: i32,
    /// A string describing the error
    pub message: String,
    /// Additional data specific to the error
    pub data: Option<JsonValue>
}

/// Create a standard error responses
pub fn standard_error(code: StandardError, data: Option<JsonValue>) -> RpcError {
    match code {
        StandardError::ParseError => RpcError {
            code: -32700,
            message: "Parse error".to_string(),
            data: data
        },
        StandardError::InvalidRequest => RpcError {
            code: -32600,
            message: "Invalid Request".to_string(),
            data: data
        },
        StandardError::MethodNotFound => RpcError {
            code: -32601,
            message: "Method not found".to_string(),
            data: data
        },
        StandardError::InvalidParams => RpcError {
            code: -32602,
            message: "Invalid params".to_string(),
            data: data
        },
        StandardError::InternalError => RpcError {
            code: -32603,
            message: "Internal error".to_string(),
            data: data
        },
    }
}

/// Converts a Rust `Result` to a JSONRPC response object
pub fn result_to_response(result: Result<JsonValue, RpcError>, id: JsonValue) -> Response {
    match result {
        Ok(data) => Response { result: Some(data), error: None, id: id },
        Err(err) => Response { result: None, error: Some(err), id: id }
    }
}

serde_struct_impl!(
    RpcError,
    rpc_error_mod,
    code,
    message,
    data
);

#[cfg(test)]
mod tests {
    use super::StandardError::{ParseError, InvalidRequest, MethodNotFound, InvalidParams, InternalError};
    use super::{standard_error, result_to_response};

    use json::value::Value as JsonValue;

    #[test]
    fn test_parse_error() {
        let resp = result_to_response(Err(standard_error(ParseError, None)), JsonValue::U64(1));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::U64(1));
        assert_eq!(resp.error.unwrap().code, -32700);
    }

    #[test]
    fn test_invalid_request() {
        let resp = result_to_response(Err(standard_error(InvalidRequest, None)), JsonValue::I64(1));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::I64(1));
        assert_eq!(resp.error.unwrap().code, -32600);
    }

    #[test]
    fn test_method_not_found() {
        let resp = result_to_response(Err(standard_error(MethodNotFound, None)), JsonValue::U64(1));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::U64(1));
        assert_eq!(resp.error.unwrap().code, -32601);
    }

    #[test]
    fn test_invalid_params() {
        let resp = result_to_response(Err(standard_error(InvalidParams, None)), JsonValue::String("123".to_string()));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::String("123".to_string()));
        assert_eq!(resp.error.unwrap().code, -32602);
    }

    #[test]
    fn test_internal_error() {
        let resp = result_to_response(Err(standard_error(InternalError, None)), JsonValue::I64(-1));
        assert!(resp.result.is_none());
        assert!(resp.error.is_some());
        assert_eq!(resp.id, JsonValue::I64(-1));
        assert_eq!(resp.error.unwrap().code, -32603);
    }
}

<|endoftext|>


<commit_before>macro_rules! impl_error_conversion {
    ($err_name:ident, $($from_ty:ty => $to_ty:ident,)+) => {
        $(
        impl From<$from_ty> for $err_name {
            fn from(f: $from_ty) -> $err_name {
                $err_name::$to_ty(f)
            }
        }
        )+
    };
}

#[derive(Fail, Debug)]
pub enum Error {
    #[fail(display = "io error")]
    Io(#[cause] ::std::io::Error),

    #[fail(display = "MAL error")]
    MALError(#[cause] ::mal::error::MALError),

    #[fail(display = "sync service error")]
    BackendError(#[cause] BackendError),

    #[fail(display = "error processing series")]
    SeriesError(#[cause] SeriesError),

    #[fail(display = "config error")]
    ConfigError(#[cause] ConfigError),

    #[fail(display = "path to [{}] not found. Try setting it with -p", _0)]
    SeriesNotFound(String),

    #[fail(display = "no information about the series to watch was provided")]
    NoSeriesInfoProvided,
}

impl_error_conversion!(Error,
    ::std::io::Error => Io,
    ::mal::error::MALError => MALError,
    BackendError => BackendError,
    SeriesError => SeriesError,
    ConfigError => ConfigError,
);

#[derive(Fail, Debug)]
pub enum SeriesError {
    #[fail(display = "io error")]
    Io(#[cause] ::std::io::Error),

    #[fail(display = "MAL error")]
    MALError(#[cause] ::mal::error::MALError),

    #[fail(display = "input error")]
    InputError(#[cause] InputError),

    #[fail(display = "error serializing toml")]
    TomlSerialize(#[cause] ::toml::ser::Error),

    #[fail(display = "error deserializing toml")]
    TomlDeserialize(#[cause] ::toml::de::Error),

    #[fail(display = "failed to open video player")]
    FailedToOpenPlayer(#[cause] ::std::io::Error),

    #[fail(display = "episode number parse failed")]
    EpisodeNumParseFailed(#[cause] ::std::num::ParseIntError),

    #[fail(display = "no episodes found")]
    NoEpisodesFound,

    #[fail(display = "multiple series found")]
    MultipleSeriesFound,

    #[fail(display = "unable to get filename")]
    UnableToGetFilename,

    #[fail(display = "failed to get regex captures on episode")]
    EpisodeRegexCaptureFailed,

    #[fail(display = "specified path is not a directory: {}", _0)]
    NotADirectory(String),

    #[fail(display = "episode {} not found", _0)]
    EpisodeNotFound(u32),

    #[fail(display = "no anime with id {} found with name [{}] on MAL", _0, _1)]
    UnknownAnimeID(u32, String),
}

impl_error_conversion!(SeriesError,
    ::std::io::Error => Io,
    ::mal::error::MALError => MALError,
    InputError => InputError,
    ::toml::ser::Error => TomlSerialize,
    ::toml::de::Error => TomlDeserialize,
);

#[derive(Fail, Debug)]
pub enum InputError {
    #[fail(display = "failed to read line")]
    ReadFailed(#[cause] ::std::io::Error),

    #[fail(display = "failed to parse input string to number")]
    IntParseFailed(#[cause] ::std::num::ParseIntError),
}

#[derive(Fail, Debug)]
pub enum ConfigError {
    #[fail(display = "io error")]
    Io(#[cause] ::std::io::Error),

    #[fail(display = "input is not valid UTF8")]
    FromUtf8Error(#[cause] ::std::string::FromUtf8Error),

    #[fail(display = "error serializing toml")]
    TomlSerialize(#[cause] ::toml::ser::Error),

    #[fail(display = "error deserializing toml")]
    TomlDeserialize(#[cause] ::toml::de::Error),

    #[fail(display = "access token decode failed")]
    FailedTokenDecode(#[cause] ::base64::DecodeError),

    #[fail(display = "access token not set for sync service")]
    TokenNotSet,
}

impl_error_conversion!(ConfigError,
    ::std::io::Error => Io,
    ::std::string::FromUtf8Error => FromUtf8Error,
    ::toml::ser::Error => TomlSerialize,
    ::toml::de::Error => TomlDeserialize,
);

#[derive(Fail, Debug)]
pub enum BackendError {
    #[fail(display = "io error")]
    Io(#[cause] ::std::io::Error),
}
<commit_msg>Add required error variants to support the new backend system<commit_after>macro_rules! impl_error_conversion {
    ($err_name:ident, $($from_ty:ty => $to_ty:ident,)+) => {
        $(
        impl From<$from_ty> for $err_name {
            fn from(f: $from_ty) -> $err_name {
                $err_name::$to_ty(f)
            }
        }
        )+
    };
}

#[derive(Fail, Debug)]
pub enum Error {
    #[fail(display = "io error")]
    Io(#[cause] ::std::io::Error),

    #[fail(display = "MAL error")]
    MALError(#[cause] ::mal::error::MALError),

    #[fail(display = "sync service error")]
    BackendError(#[cause] BackendError),

    #[fail(display = "error processing series")]
    SeriesError(#[cause] SeriesError),

    #[fail(display = "config error")]
    ConfigError(#[cause] ConfigError),

    #[fail(display = "path to [{}] not found. Try setting it with -p", _0)]
    SeriesNotFound(String),

    #[fail(display = "no information about the series to watch was provided")]
    NoSeriesInfoProvided,
}

impl_error_conversion!(Error,
    ::std::io::Error => Io,
    ::mal::error::MALError => MALError,
    BackendError => BackendError,
    SeriesError => SeriesError,
    ConfigError => ConfigError,
);

#[derive(Fail, Debug)]
pub enum SeriesError {
    #[fail(display = "io error")]
    Io(#[cause] ::std::io::Error),

    #[fail(display = "MAL error")]
    MALError(#[cause] ::mal::error::MALError),

    #[fail(display = "input error")]
    InputError(#[cause] InputError),

    #[fail(display = "error serializing toml")]
    TomlSerialize(#[cause] ::toml::ser::Error),

    #[fail(display = "error deserializing toml")]
    TomlDeserialize(#[cause] ::toml::de::Error),

    #[fail(display = "failed to open video player")]
    FailedToOpenPlayer(#[cause] ::std::io::Error),

    #[fail(display = "episode number parse failed")]
    EpisodeNumParseFailed(#[cause] ::std::num::ParseIntError),

    #[fail(display = "sync service error")]
    Backend(#[cause] BackendError),

    #[fail(display = "no episodes found")]
    NoEpisodesFound,

    #[fail(display = "multiple series found")]
    MultipleSeriesFound,

    #[fail(display = "unable to get filename")]
    UnableToGetFilename,

    #[fail(display = "failed to get regex captures on episode")]
    EpisodeRegexCaptureFailed,

    #[fail(display = "specified path is not a directory: {}", _0)]
    NotADirectory(String),

    #[fail(display = "episode {} not found", _0)]
    EpisodeNotFound(u32),
}

impl_error_conversion!(SeriesError,
    ::std::io::Error => Io,
    ::mal::error::MALError => MALError,
    InputError => InputError,
    ::toml::ser::Error => TomlSerialize,
    ::toml::de::Error => TomlDeserialize,
    BackendError => Backend,
);

#[derive(Fail, Debug)]
pub enum InputError {
    #[fail(display = "failed to read line")]
    ReadFailed(#[cause] ::std::io::Error),

    #[fail(display = "failed to parse input string to number")]
    IntParseFailed(#[cause] ::std::num::ParseIntError),
}

#[derive(Fail, Debug)]
pub enum ConfigError {
    #[fail(display = "io error")]
    Io(#[cause] ::std::io::Error),

    #[fail(display = "input is not valid UTF8")]
    FromUtf8Error(#[cause] ::std::string::FromUtf8Error),

    #[fail(display = "error serializing toml")]
    TomlSerialize(#[cause] ::toml::ser::Error),

    #[fail(display = "error deserializing toml")]
    TomlDeserialize(#[cause] ::toml::de::Error),

    #[fail(display = "access token decode failed")]
    FailedTokenDecode(#[cause] ::base64::DecodeError),

    #[fail(display = "access token not set for sync service")]
    TokenNotSet,
}

impl_error_conversion!(ConfigError,
    ::std::io::Error => Io,
    ::std::string::FromUtf8Error => FromUtf8Error,
    ::toml::ser::Error => TomlSerialize,
    ::toml::de::Error => TomlDeserialize,
);

#[derive(Fail, Debug)]
pub enum BackendError {
    #[fail(display = "io error")]
    Io(#[cause] ::std::io::Error),

    #[fail(display = "config error")]
    ConfigError(#[cause] ConfigError),

    #[fail(display = "HTTP error")]
    HttpError(#[cause] ::reqwest::Error),

    #[fail(display = "json error")]
    Json(#[cause] ::serde_json::Error),

    #[fail(display = "received invalid JSON response")]
    InvalidJsonResponse,

    #[fail(display = "list update failed: {}", _0)]
    ListUpdate(String),
}

impl_error_conversion!(BackendError,
    ::std::io::Error => Io,
    ConfigError => ConfigError,
    ::reqwest::Error => HttpError,
    ::serde_json::Error => Json,
);
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// 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.

//! When serializing or deserializing JSON goes wrong.

use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;

use serde::de;
use serde::ser;

/// This type represents all possible errors that can occur when serializing or
/// deserializing JSON data.
pub struct Error {
    /// This `Box` allows us to keep the size of `Error` as small as possible. A
    /// larger `Error` type was substantially slower due to all the functions
    /// that pass around `Result<T, Error>`.
    err: Box<ErrorImpl>,
}

/// Alias for a `Result` with the error type `serde_json::Error`.
pub type Result<T> = result::Result<T, Error>;

impl Error {
    /// One-based line number at which the error was detected.
    ///
    /// Characters in the first line of the input (before the first newline
    /// character) are in line 1.
    pub fn line(&self) -> usize {
        self.err.line
    }

    /// One-based column number at which the error was detected.
    ///
    /// The first character in the input and any characters immediately
    /// following a newline character are in column 1.
    ///
    /// Note that errors may occur in column 0, for example if a read from an IO
    /// stream fails immediately following a previously read newline character.
    pub fn column(&self) -> usize {
        self.err.column
    }

    /// Categorizes the cause of this error.
    ///
    /// - `Category::Io` - failure to read or write bytes on an IO stream
    /// - `Category::Syntax` - input that is not syntactically valid JSON
    /// - `Category::Data` - input data that is semantically incorrect
    /// - `Category::Eof` - unexpected end of the input data
    pub fn classify(&self) -> Category {
        match self.err.code {
            ErrorCode::Message(_) => Category::Data,
            ErrorCode::Io(_) => Category::Io,
            ErrorCode::EofWhileParsingList |
            ErrorCode::EofWhileParsingObject |
            ErrorCode::EofWhileParsingString |
            ErrorCode::EofWhileParsingValue => Category::Eof,
            ErrorCode::ExpectedColon |
            ErrorCode::ExpectedListCommaOrEnd |
            ErrorCode::ExpectedObjectCommaOrEnd |
            ErrorCode::ExpectedObjectOrArray |
            ErrorCode::ExpectedSomeIdent |
            ErrorCode::ExpectedSomeValue |
            ErrorCode::ExpectedSomeString |
            ErrorCode::InvalidEscape |
            ErrorCode::InvalidNumber |
            ErrorCode::NumberOutOfRange |
            ErrorCode::InvalidUnicodeCodePoint |
            ErrorCode::KeyMustBeAString |
            ErrorCode::LoneLeadingSurrogateInHexEscape |
            ErrorCode::TrailingComma |
            ErrorCode::TrailingCharacters |
            ErrorCode::UnexpectedEndOfHexEscape |
            ErrorCode::RecursionLimitExceeded => Category::Syntax,
        }
    }

    /// Returns true if this error was caused by a failure to read or write
    /// bytes on an IO stream.
    pub fn is_io(&self) -> bool {
        self.classify() == Category::Io
    }

    /// Returns true if this error was caused by input that was not
    /// syntactically valid JSON.
    pub fn is_syntax(&self) -> bool {
        self.classify() == Category::Syntax
    }

    /// Returns true if this error was caused by input data that was
    /// semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    pub fn is_data(&self) -> bool {
        self.classify() == Category::Data
    }

    /// Returns true if this error was caused by prematurely reaching the end of
    /// the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    pub fn is_eof(&self) -> bool {
        self.classify() == Category::Eof
    }
}

/// Categorizes the cause of a `serde_json::Error`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
    /// The error was caused by a failure to read or write bytes on an IO
    /// stream.
    Io,

    /// The error was caused by input that was not syntactically valid JSON.
    Syntax,

    /// The error was caused by input data that was semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    Data,

    /// The error was caused by prematurely reaching the end of the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    Eof,
}

#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
impl From<Error> for io::Error {
    /// Convert a `serde_json::Error` into an `io::Error`.
    ///
    /// JSON syntax and data errors are turned into `InvalidData` IO errors.
    /// EOF errors are turned into `UnexpectedEof` IO errors.
    ///
    /// ```rust
    /// use std::io;
    ///
    /// enum MyError {
    ///     Io(io::Error),
    ///     Json(serde_json::Error),
    /// }
    ///
    /// impl From<serde_json::Error> for MyError {
    ///     fn from(err: serde_json::Error) -> MyError {
    ///         use serde_json::error::Category;
    ///         match err.classify() {
    ///             Category::Io => {
    ///                 MyError::Io(err.into())
    ///             }
    ///             Category::Syntax | Category::Data | Category::Eof => {
    ///                 MyError::Json(err)
    ///             }
    ///         }
    ///     }
    /// }
    /// ```
    fn from(j: Error) -> Self {
        if let ErrorCode::Io(err) = j.err.code {
            err
        } else {
            match j.classify() {
                Category::Io => unreachable!(),
                Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j),
                Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j),
            }
        }
    }
}

#[derive(Debug)]
struct ErrorImpl {
    code: ErrorCode,
    line: usize,
    column: usize,
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
#[derive(Debug)]
pub enum ErrorCode {
    /// Catchall for syntax error messages
    Message(String),

    /// Some IO error occurred while serializing or deserializing.
    Io(io::Error),

    /// EOF while parsing a list.
    EofWhileParsingList,

    /// EOF while parsing an object.
    EofWhileParsingObject,

    /// EOF while parsing a string.
    EofWhileParsingString,

    /// EOF while parsing a JSON value.
    EofWhileParsingValue,

    /// Expected this character to be a `':'`.
    ExpectedColon,

    /// Expected this character to be either a `','` or a `']'`.
    ExpectedListCommaOrEnd,

    /// Expected this character to be either a `','` or a `'}'`.
    ExpectedObjectCommaOrEnd,

    /// Expected this character to be either a `'{'` or a `'['`.
    ExpectedObjectOrArray,

    /// Expected to parse either a `true`, `false`, or a `null`.
    ExpectedSomeIdent,

    /// Expected this character to start a JSON value.
    ExpectedSomeValue,

    /// Expected this character to start a JSON string.
    ExpectedSomeString,

    /// Invalid hex escape code.
    InvalidEscape,

    /// Invalid number.
    InvalidNumber,

    /// Number is bigger than the maximum value of its type.
    NumberOutOfRange,

    /// Invalid unicode code point.
    InvalidUnicodeCodePoint,

    /// Object key is not a string.
    KeyMustBeAString,

    /// Lone leading surrogate in hex escape.
    LoneLeadingSurrogateInHexEscape,

    /// JSON has a comma after the last value in an array or map.
    TrailingComma,

    /// JSON has non-whitespace trailing characters after the value.
    TrailingCharacters,

    /// Unexpected end of hex excape.
    UnexpectedEndOfHexEscape,

    /// Encountered nesting of JSON maps and arrays more than 128 layers deep.
    RecursionLimitExceeded,
}

impl Error {
    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: code,
                    line: line,
                    column: column,
                },
            ),
        }
    }

    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn io(error: io::Error) -> Self {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Io(error),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }

    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn fix_position<F>(self, f: F) -> Self
    where
        F: FnOnce(ErrorCode) -> Error,
    {
        if self.err.line == 0 {
            f(self.err.code)
        } else {
            self
        }
    }
}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCode::Message(ref msg) => f.write_str(msg),
            ErrorCode::Io(ref err) => Display::fmt(err, f),
            ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"),
            ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
            ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"),
            ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
            ErrorCode::ExpectedColon => f.write_str("expected `:`"),
            ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
            ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
            ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"),
            ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"),
            ErrorCode::ExpectedSomeValue => f.write_str("expected value"),
            ErrorCode::ExpectedSomeString => f.write_str("expected string"),
            ErrorCode::InvalidEscape => f.write_str("invalid escape"),
            ErrorCode::InvalidNumber => f.write_str("invalid number"),
            ErrorCode::NumberOutOfRange => f.write_str("number out of range"),
            ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
            ErrorCode::KeyMustBeAString => f.write_str("key must be a string"),
            ErrorCode::LoneLeadingSurrogateInHexEscape => {
                f.write_str("lone leading surrogate in hex escape")
            }
            ErrorCode::TrailingComma => f.write_str("trailing comma"),
            ErrorCode::TrailingCharacters => f.write_str("trailing characters"),
            ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
            ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self.err.code {
            ErrorCode::Io(ref err) => error::Error::description(err),
            _ => {
                // If you want a better message, use Display::fmt or to_string().
                "JSON error"
            }
        }
    }

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

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

impl Display for ErrorImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.line == 0 {
            Display::fmt(&self.code, f)
        } else {
            write!(
                f,
                "{} at line {} column {}",
                self.code,
                self.line,
                self.column
            )
        }
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&*self.err, f)
    }
}

impl de::Error for Error {
    fn custom<T: Display>(msg: T) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Message(msg.to_string()),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }

    fn invalid_type(unexp: de::Unexpected, exp: &de::Expected) -> Self {
        if let de::Unexpected::Unit = unexp {
            Error::custom(format_args!("invalid type: null, expected {}", exp))
        } else {
            Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
        }
    }
}

impl ser::Error for Error {
    fn custom<T: Display>(msg: T) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Message(msg.to_string()),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }
}
<commit_msg>Decrease size of ErrorCode from 32 bytes to 24 bytes<commit_after>// Copyright 2017 Serde Developers
//
// 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.

//! When serializing or deserializing JSON goes wrong.

use std::error;
use std::fmt::{self, Debug, Display};
use std::io;
use std::result;

use serde::de;
use serde::ser;

/// This type represents all possible errors that can occur when serializing or
/// deserializing JSON data.
pub struct Error {
    /// This `Box` allows us to keep the size of `Error` as small as possible. A
    /// larger `Error` type was substantially slower due to all the functions
    /// that pass around `Result<T, Error>`.
    err: Box<ErrorImpl>,
}

/// Alias for a `Result` with the error type `serde_json::Error`.
pub type Result<T> = result::Result<T, Error>;

impl Error {
    /// One-based line number at which the error was detected.
    ///
    /// Characters in the first line of the input (before the first newline
    /// character) are in line 1.
    pub fn line(&self) -> usize {
        self.err.line
    }

    /// One-based column number at which the error was detected.
    ///
    /// The first character in the input and any characters immediately
    /// following a newline character are in column 1.
    ///
    /// Note that errors may occur in column 0, for example if a read from an IO
    /// stream fails immediately following a previously read newline character.
    pub fn column(&self) -> usize {
        self.err.column
    }

    /// Categorizes the cause of this error.
    ///
    /// - `Category::Io` - failure to read or write bytes on an IO stream
    /// - `Category::Syntax` - input that is not syntactically valid JSON
    /// - `Category::Data` - input data that is semantically incorrect
    /// - `Category::Eof` - unexpected end of the input data
    pub fn classify(&self) -> Category {
        match self.err.code {
            ErrorCode::Message(_) => Category::Data,
            ErrorCode::Io(_) => Category::Io,
            ErrorCode::EofWhileParsingList |
            ErrorCode::EofWhileParsingObject |
            ErrorCode::EofWhileParsingString |
            ErrorCode::EofWhileParsingValue => Category::Eof,
            ErrorCode::ExpectedColon |
            ErrorCode::ExpectedListCommaOrEnd |
            ErrorCode::ExpectedObjectCommaOrEnd |
            ErrorCode::ExpectedObjectOrArray |
            ErrorCode::ExpectedSomeIdent |
            ErrorCode::ExpectedSomeValue |
            ErrorCode::ExpectedSomeString |
            ErrorCode::InvalidEscape |
            ErrorCode::InvalidNumber |
            ErrorCode::NumberOutOfRange |
            ErrorCode::InvalidUnicodeCodePoint |
            ErrorCode::KeyMustBeAString |
            ErrorCode::LoneLeadingSurrogateInHexEscape |
            ErrorCode::TrailingComma |
            ErrorCode::TrailingCharacters |
            ErrorCode::UnexpectedEndOfHexEscape |
            ErrorCode::RecursionLimitExceeded => Category::Syntax,
        }
    }

    /// Returns true if this error was caused by a failure to read or write
    /// bytes on an IO stream.
    pub fn is_io(&self) -> bool {
        self.classify() == Category::Io
    }

    /// Returns true if this error was caused by input that was not
    /// syntactically valid JSON.
    pub fn is_syntax(&self) -> bool {
        self.classify() == Category::Syntax
    }

    /// Returns true if this error was caused by input data that was
    /// semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    pub fn is_data(&self) -> bool {
        self.classify() == Category::Data
    }

    /// Returns true if this error was caused by prematurely reaching the end of
    /// the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    pub fn is_eof(&self) -> bool {
        self.classify() == Category::Eof
    }
}

/// Categorizes the cause of a `serde_json::Error`.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Category {
    /// The error was caused by a failure to read or write bytes on an IO
    /// stream.
    Io,

    /// The error was caused by input that was not syntactically valid JSON.
    Syntax,

    /// The error was caused by input data that was semantically incorrect.
    ///
    /// For example, JSON containing a number is semantically incorrect when the
    /// type being deserialized into holds a String.
    Data,

    /// The error was caused by prematurely reaching the end of the input data.
    ///
    /// Callers that process streaming input may be interested in retrying the
    /// deserialization once more data is available.
    Eof,
}

#[cfg_attr(feature = "cargo-clippy", allow(fallible_impl_from))]
impl From<Error> for io::Error {
    /// Convert a `serde_json::Error` into an `io::Error`.
    ///
    /// JSON syntax and data errors are turned into `InvalidData` IO errors.
    /// EOF errors are turned into `UnexpectedEof` IO errors.
    ///
    /// ```rust
    /// use std::io;
    ///
    /// enum MyError {
    ///     Io(io::Error),
    ///     Json(serde_json::Error),
    /// }
    ///
    /// impl From<serde_json::Error> for MyError {
    ///     fn from(err: serde_json::Error) -> MyError {
    ///         use serde_json::error::Category;
    ///         match err.classify() {
    ///             Category::Io => {
    ///                 MyError::Io(err.into())
    ///             }
    ///             Category::Syntax | Category::Data | Category::Eof => {
    ///                 MyError::Json(err)
    ///             }
    ///         }
    ///     }
    /// }
    /// ```
    fn from(j: Error) -> Self {
        if let ErrorCode::Io(err) = j.err.code {
            err
        } else {
            match j.classify() {
                Category::Io => unreachable!(),
                Category::Syntax | Category::Data => io::Error::new(io::ErrorKind::InvalidData, j),
                Category::Eof => io::Error::new(io::ErrorKind::UnexpectedEof, j),
            }
        }
    }
}

#[derive(Debug)]
struct ErrorImpl {
    code: ErrorCode,
    line: usize,
    column: usize,
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
#[derive(Debug)]
pub enum ErrorCode {
    /// Catchall for syntax error messages
    Message(Box<str>),

    /// Some IO error occurred while serializing or deserializing.
    Io(io::Error),

    /// EOF while parsing a list.
    EofWhileParsingList,

    /// EOF while parsing an object.
    EofWhileParsingObject,

    /// EOF while parsing a string.
    EofWhileParsingString,

    /// EOF while parsing a JSON value.
    EofWhileParsingValue,

    /// Expected this character to be a `':'`.
    ExpectedColon,

    /// Expected this character to be either a `','` or a `']'`.
    ExpectedListCommaOrEnd,

    /// Expected this character to be either a `','` or a `'}'`.
    ExpectedObjectCommaOrEnd,

    /// Expected this character to be either a `'{'` or a `'['`.
    ExpectedObjectOrArray,

    /// Expected to parse either a `true`, `false`, or a `null`.
    ExpectedSomeIdent,

    /// Expected this character to start a JSON value.
    ExpectedSomeValue,

    /// Expected this character to start a JSON string.
    ExpectedSomeString,

    /// Invalid hex escape code.
    InvalidEscape,

    /// Invalid number.
    InvalidNumber,

    /// Number is bigger than the maximum value of its type.
    NumberOutOfRange,

    /// Invalid unicode code point.
    InvalidUnicodeCodePoint,

    /// Object key is not a string.
    KeyMustBeAString,

    /// Lone leading surrogate in hex escape.
    LoneLeadingSurrogateInHexEscape,

    /// JSON has a comma after the last value in an array or map.
    TrailingComma,

    /// JSON has non-whitespace trailing characters after the value.
    TrailingCharacters,

    /// Unexpected end of hex excape.
    UnexpectedEndOfHexEscape,

    /// Encountered nesting of JSON maps and arrays more than 128 layers deep.
    RecursionLimitExceeded,
}

impl Error {
    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn syntax(code: ErrorCode, line: usize, column: usize) -> Self {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: code,
                    line: line,
                    column: column,
                },
            ),
        }
    }

    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn io(error: io::Error) -> Self {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Io(error),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }

    // Not public API. Should be pub(crate).
    #[doc(hidden)]
    pub fn fix_position<F>(self, f: F) -> Self
    where
        F: FnOnce(ErrorCode) -> Error,
    {
        if self.err.line == 0 {
            f(self.err.code)
        } else {
            self
        }
    }
}

impl Display for ErrorCode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ErrorCode::Message(ref msg) => f.write_str(msg),
            ErrorCode::Io(ref err) => Display::fmt(err, f),
            ErrorCode::EofWhileParsingList => f.write_str("EOF while parsing a list"),
            ErrorCode::EofWhileParsingObject => f.write_str("EOF while parsing an object"),
            ErrorCode::EofWhileParsingString => f.write_str("EOF while parsing a string"),
            ErrorCode::EofWhileParsingValue => f.write_str("EOF while parsing a value"),
            ErrorCode::ExpectedColon => f.write_str("expected `:`"),
            ErrorCode::ExpectedListCommaOrEnd => f.write_str("expected `,` or `]`"),
            ErrorCode::ExpectedObjectCommaOrEnd => f.write_str("expected `,` or `}`"),
            ErrorCode::ExpectedObjectOrArray => f.write_str("expected `{` or `[`"),
            ErrorCode::ExpectedSomeIdent => f.write_str("expected ident"),
            ErrorCode::ExpectedSomeValue => f.write_str("expected value"),
            ErrorCode::ExpectedSomeString => f.write_str("expected string"),
            ErrorCode::InvalidEscape => f.write_str("invalid escape"),
            ErrorCode::InvalidNumber => f.write_str("invalid number"),
            ErrorCode::NumberOutOfRange => f.write_str("number out of range"),
            ErrorCode::InvalidUnicodeCodePoint => f.write_str("invalid unicode code point"),
            ErrorCode::KeyMustBeAString => f.write_str("key must be a string"),
            ErrorCode::LoneLeadingSurrogateInHexEscape => {
                f.write_str("lone leading surrogate in hex escape")
            }
            ErrorCode::TrailingComma => f.write_str("trailing comma"),
            ErrorCode::TrailingCharacters => f.write_str("trailing characters"),
            ErrorCode::UnexpectedEndOfHexEscape => f.write_str("unexpected end of hex escape"),
            ErrorCode::RecursionLimitExceeded => f.write_str("recursion limit exceeded"),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self.err.code {
            ErrorCode::Io(ref err) => error::Error::description(err),
            _ => {
                // If you want a better message, use Display::fmt or to_string().
                "JSON error"
            }
        }
    }

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

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

impl Display for ErrorImpl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.line == 0 {
            Display::fmt(&self.code, f)
        } else {
            write!(
                f,
                "{} at line {} column {}",
                self.code,
                self.line,
                self.column
            )
        }
    }
}

// Remove two layers of verbosity from the debug representation. Humans often
// end up seeing this representation because it is what unwrap() shows.
impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&*self.err, f)
    }
}

impl de::Error for Error {
    fn custom<T: Display>(msg: T) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Message(msg.to_string().into_boxed_str()),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }

    fn invalid_type(unexp: de::Unexpected, exp: &de::Expected) -> Self {
        if let de::Unexpected::Unit = unexp {
            Error::custom(format_args!("invalid type: null, expected {}", exp))
        } else {
            Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
        }
    }
}

impl ser::Error for Error {
    fn custom<T: Display>(msg: T) -> Error {
        Error {
            err: Box::new(
                ErrorImpl {
                    code: ErrorCode::Message(msg.to_string().into_boxed_str()),
                    line: 0,
                    column: 0,
                },
            ),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ffi::CStr;
use std::error;
use std::fmt;
use std::str;
use translate::*;
use glib_ffi;

glib_wrapper! {
    pub struct Error(Boxed<glib_ffi::GError>);

    match fn {
        copy => |ptr| glib_ffi::g_error_copy(ptr),
        free => |ptr| glib_ffi::g_error_free(ptr),
    }
}

impl Error {
    /// Creates an error with supplied error enum variant and message.
    pub fn new<T: ErrorDomain>(error: T, message: &str) -> Error {
        unsafe {
            from_glib_full(
                glib_ffi::g_error_new_literal(T::domain(), error.code(), message.to_glib_none().0))
        }
    }

    /// Tries to match against an error enum.
    ///
    /// Example
    /// ```ignore
    /// if let Some(file_error) = error.matches::<FileError>() {
    ///     match file_error {
    ///         Exist => ...
    ///         Isdir => ...
    ///         ...
    ///     }
    /// }
    /// ```
    pub fn matches<T: ErrorDomain>(&self) -> Option<T> {
        if self.0.domain == T::domain() {
            T::from(self.0.code)
        }
        else {
            None
        }
    }

    fn message(&self) -> &str {
        unsafe {
            let bytes = CStr::from_ptr(self.0.message).to_bytes();
            str::from_utf8(bytes).unwrap_or_else(|err| {
                str::from_utf8(&bytes[..err.valid_up_to()]).unwrap()
            })
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.message()
    }
}

/// `GLib` error domain.
///
/// This trait is implemented by error enums and is not intended for end users.
pub trait ErrorDomain: Copy {
    /// Returns the quark identifying the error domain.
    ///
    /// As returned from `g_some_error_quark`.
    fn domain() -> glib_ffi::GQuark;

    /// Gets the integer representation of the variant.
    fn code(self) -> i32;

    /// Tries to convert an integer code to an enum variant.
    ///
    /// By convention, the `Failed` variant, if present, is a catch-all,
    /// i.e. any unrecognized codes map to it.
    fn from(code: i32) -> Option<Self> where Self: Sized;
}
<commit_msg>Add temporary shim to unbreak gdk build<commit_after>// Copyright 2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ffi::CStr;
use std::error;
use std::fmt;
use std::str;
use translate::*;
use glib_ffi;

glib_wrapper! {
    pub struct Error(Boxed<glib_ffi::GError>);

    match fn {
        copy => |ptr| glib_ffi::g_error_copy(ptr),
        free => |ptr| glib_ffi::g_error_free(ptr),
    }
}

impl Error {
    /// Creates an error with supplied error enum variant and message.
    pub fn new<T: ErrorDomain>(error: T, message: &str) -> Error {
        unsafe {
            from_glib_full(
                glib_ffi::g_error_new_literal(T::domain(), error.code(), message.to_glib_none().0))
        }
    }

    /// Tries to match against an error enum.
    ///
    /// Example
    /// ```ignore
    /// if let Some(file_error) = error.matches::<FileError>() {
    ///     match file_error {
    ///         Exist => ...
    ///         Isdir => ...
    ///         ...
    ///     }
    /// }
    /// ```
    pub fn matches<T: ErrorDomain>(&self) -> Option<T> {
        if self.0.domain == T::domain() {
            T::from(self.0.code)
        }
        else {
            None
        }
    }

    fn message(&self) -> &str {
        unsafe {
            let bytes = CStr::from_ptr(self.0.message).to_bytes();
            str::from_utf8(bytes).unwrap_or_else(|err| {
                str::from_utf8(&bytes[..err.valid_up_to()]).unwrap()
            })
        }
    }

    // backcompat shim
    pub fn wrap(ptr: *mut glib_ffi::GError) -> Error {
        unsafe { from_glib_full(ptr) }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.message()
    }
}

/// `GLib` error domain.
///
/// This trait is implemented by error enums and is not intended for end users.
pub trait ErrorDomain: Copy {
    /// Returns the quark identifying the error domain.
    ///
    /// As returned from `g_some_error_quark`.
    fn domain() -> glib_ffi::GQuark;

    /// Gets the integer representation of the variant.
    fn code(self) -> i32;

    /// Tries to convert an integer code to an enum variant.
    ///
    /// By convention, the `Failed` variant, if present, is a catch-all,
    /// i.e. any unrecognized codes map to it.
    fn from(code: i32) -> Option<Self> where Self: Sized;
}
<|endoftext|>


<commit_before>// Copyright 2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ffi::CStr;
use std::error;
use std::fmt;
use std::str;
use translate::*;
use glib_ffi;

glib_wrapper! {
    pub struct Error(Boxed<glib_ffi::GError>);

    match fn {
        copy => |ptr| glib_ffi::g_error_copy(ptr),
        free => |ptr| glib_ffi::g_error_free(ptr),
    }
}

impl Error {
    /// Creates an error with supplied error enum variant and message.
    pub fn new<T: ErrorDomain>(error: T, message: &str) -> Error {
        unsafe {
            from_glib_full(
                glib_ffi::g_error_new_literal(T::domain(), error.code(), message.to_glib_none().0))
        }
    }

    /// Tries to match against an error enum.
    ///
    /// Example
    /// ```ignore
    /// if let Some(file_error) = error.matches::<FileError>() {
    ///     match file_error {
    ///         Exist => ...
    ///         Isdir => ...
    ///         ...
    ///     }
    /// }
    /// ```
    pub fn matches<T: ErrorDomain>(&self) -> Option<T> {
        if self.0.domain == T::domain() {
            T::from(self.0.code)
        }
        else {
            None
        }
    }

    fn message(&self) -> &str {
        unsafe {
            let bytes = CStr::from_ptr(self.0.message).to_bytes();
            str::from_utf8(bytes).unwrap_or_else(|err| {
                str::from_utf8(&bytes[..err.valid_up_to()]).unwrap()
            })
        }
    }

    // backcompat shim
    pub fn wrap(ptr: *mut glib_ffi::GError) -> Error {
        unsafe { from_glib_full(ptr) }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.message()
    }
}

/// `GLib` error domain.
///
/// This trait is implemented by error enums and is not intended for end users.
pub trait ErrorDomain: Copy {
    /// Returns the quark identifying the error domain.
    ///
    /// As returned from `g_some_error_quark`.
    fn domain() -> glib_ffi::GQuark;

    /// Gets the integer representation of the variant.
    fn code(self) -> i32;

    /// Tries to convert an integer code to an enum variant.
    ///
    /// By convention, the `Failed` variant, if present, is a catch-all,
    /// i.e. any unrecognized codes map to it.
    fn from(code: i32) -> Option<Self> where Self: Sized;
}
<commit_msg>Rename `Error::matches` to `typed` for consistency with `Value::typed`<commit_after>// Copyright 2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ffi::CStr;
use std::error;
use std::fmt;
use std::str;
use translate::*;
use glib_ffi;

glib_wrapper! {
    pub struct Error(Boxed<glib_ffi::GError>);

    match fn {
        copy => |ptr| glib_ffi::g_error_copy(ptr),
        free => |ptr| glib_ffi::g_error_free(ptr),
    }
}

impl Error {
    /// Creates an error with supplied error enum variant and message.
    pub fn new<T: ErrorDomain>(error: T, message: &str) -> Error {
        unsafe {
            from_glib_full(
                glib_ffi::g_error_new_literal(T::domain(), error.code(), message.to_glib_none().0))
        }
    }

    /// Tries to convert to a specific error enum.
    ///
    /// Returns `Some` if the error belongs to the enum's error domain and
    /// `None` otherwise.
    ///
    /// Example
    /// ```ignore
    /// if let Some(file_error) = error.typed::<FileError>() {
    ///     match file_error {
    ///         Exist => ...
    ///         Isdir => ...
    ///         ...
    ///     }
    /// }
    /// ```
    pub fn typed<T: ErrorDomain>(&self) -> Option<T> {
        if self.0.domain == T::domain() {
            T::from(self.0.code)
        }
        else {
            None
        }
    }

    fn message(&self) -> &str {
        unsafe {
            let bytes = CStr::from_ptr(self.0.message).to_bytes();
            str::from_utf8(bytes).unwrap_or_else(|err| {
                str::from_utf8(&bytes[..err.valid_up_to()]).unwrap()
            })
        }
    }

    // backcompat shim
    pub fn wrap(ptr: *mut glib_ffi::GError) -> Error {
        unsafe { from_glib_full(ptr) }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.message()
    }
}

/// `GLib` error domain.
///
/// This trait is implemented by error enums and is not intended for end users.
pub trait ErrorDomain: Copy {
    /// Returns the quark identifying the error domain.
    ///
    /// As returned from `g_some_error_quark`.
    fn domain() -> glib_ffi::GQuark;

    /// Gets the integer representation of the variant.
    fn code(self) -> i32;

    /// Tries to convert an integer code to an enum variant.
    ///
    /// By convention, the `Failed` variant, if present, is a catch-all,
    /// i.e. any unrecognized codes map to it.
    fn from(code: i32) -> Option<Self> where Self: Sized;
}
<|endoftext|>