<commit_before>//! Atomic intrinsics are implemented using a global lock for now, as Cranelift doesn't support
//! atomic operations yet.

// FIXME implement atomic instructions in Cranelift.

use crate::prelude::*;

#[cfg(feature = "jit")]
#[no_mangle]
pub static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t =
    libc::PTHREAD_MUTEX_INITIALIZER;

pub(crate) fn init_global_lock(
    module: &mut impl Module,
    bcx: &mut FunctionBuilder<'_>,
    use_jit: bool,
) {
    if use_jit {
        // When using JIT, dylibs won't find the __cg_clif_global_atomic_mutex data object defined here,
        // so instead we define it in the cg_clif dylib.

        return;
    }

    let mut data_ctx = DataContext::new();
    data_ctx.define_zeroinit(1024); // 1024 bytes should be big enough on all platforms.
    data_ctx.set_align(16);
    let atomic_mutex = module
        .declare_data(
            "__cg_clif_global_atomic_mutex",
            Linkage::Export,
            true,
            false,
        )
        .unwrap();
    module.define_data(atomic_mutex, &data_ctx).unwrap();

    let pthread_mutex_init = module
        .declare_function(
            "pthread_mutex_init",
            Linkage::Import,
            &cranelift_codegen::ir::Signature {
                call_conv: module.target_config().default_call_conv,
                params: vec![
                    AbiParam::new(
                        module.target_config().pointer_type(), /* *mut pthread_mutex_t */
                    ),
                    AbiParam::new(
                        module.target_config().pointer_type(), /* *const pthread_mutex_attr_t */
                    ),
                ],
                returns: vec![AbiParam::new(types::I32 /* c_int */)],
            },
        )
        .unwrap();

    let pthread_mutex_init = module.declare_func_in_func(pthread_mutex_init, bcx.func);

    let atomic_mutex = module.declare_data_in_func(atomic_mutex, bcx.func);
    let atomic_mutex = bcx
        .ins()
        .global_value(module.target_config().pointer_type(), atomic_mutex);

    let nullptr = bcx.ins().iconst(module.target_config().pointer_type(), 0);

    bcx.ins().call(pthread_mutex_init, &[atomic_mutex, nullptr]);
}

pub(crate) fn init_global_lock_constructor(
    module: &mut impl Module,
    constructor_name: &str,
) -> FuncId {
    let sig = Signature::new(CallConv::SystemV);
    let init_func_id = module
        .declare_function(constructor_name, Linkage::Export, &sig)
        .unwrap();

    let mut ctx = Context::new();
    ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
    {
        let mut func_ctx = FunctionBuilderContext::new();
        let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

        let block = bcx.create_block();
        bcx.switch_to_block(block);

        crate::atomic_shim::init_global_lock(module, &mut bcx, false);

        bcx.ins().return_(&[]);
        bcx.seal_all_blocks();
        bcx.finalize();
    }
    module
        .define_function(
            init_func_id,
            &mut ctx,
            &mut cranelift_codegen::binemit::NullTrapSink {},
        )
        .unwrap();

    init_func_id
}

pub(crate) fn lock_global_lock(fx: &mut FunctionCx<'_, '_, impl Module>) {
    let atomic_mutex = fx
        .cx
        .module
        .declare_data(
            "__cg_clif_global_atomic_mutex",
            Linkage::Import,
            true,
            false,
        )
        .unwrap();

    let pthread_mutex_lock = fx
        .cx
        .module
        .declare_function(
            "pthread_mutex_lock",
            Linkage::Import,
            &cranelift_codegen::ir::Signature {
                call_conv: fx.cx.module.target_config().default_call_conv,
                params: vec![AbiParam::new(
                    fx.cx.module.target_config().pointer_type(), /* *mut pthread_mutex_t */
                )],
                returns: vec![AbiParam::new(types::I32 /* c_int */)],
            },
        )
        .unwrap();

    let pthread_mutex_lock = fx
        .cx
        .module
        .declare_func_in_func(pthread_mutex_lock, fx.bcx.func);

    let atomic_mutex = fx.cx.module.declare_data_in_func(atomic_mutex, fx.bcx.func);
    let atomic_mutex = fx
        .bcx
        .ins()
        .global_value(fx.cx.module.target_config().pointer_type(), atomic_mutex);

    fx.bcx.ins().call(pthread_mutex_lock, &[atomic_mutex]);
}

pub(crate) fn unlock_global_lock(fx: &mut FunctionCx<'_, '_, impl Module>) {
    let atomic_mutex = fx
        .cx
        .module
        .declare_data(
            "__cg_clif_global_atomic_mutex",
            Linkage::Import,
            true,
            false,
        )
        .unwrap();

    let pthread_mutex_unlock = fx
        .cx
        .module
        .declare_function(
            "pthread_mutex_unlock",
            Linkage::Import,
            &cranelift_codegen::ir::Signature {
                call_conv: fx.cx.module.target_config().default_call_conv,
                params: vec![AbiParam::new(
                    fx.cx.module.target_config().pointer_type(), /* *mut pthread_mutex_t */
                )],
                returns: vec![AbiParam::new(types::I32 /* c_int */)],
            },
        )
        .unwrap();

    let pthread_mutex_unlock = fx
        .cx
        .module
        .declare_func_in_func(pthread_mutex_unlock, fx.bcx.func);

    let atomic_mutex = fx.cx.module.declare_data_in_func(atomic_mutex, fx.bcx.func);
    let atomic_mutex = fx
        .bcx
        .ins()
        .global_value(fx.cx.module.target_config().pointer_type(), atomic_mutex);

    fx.bcx.ins().call(pthread_mutex_unlock, &[atomic_mutex]);
}
<commit_msg>Fix compilation for non-unix systems<commit_after>//! Atomic intrinsics are implemented using a global lock for now, as Cranelift doesn't support
//! atomic operations yet.

// FIXME implement atomic instructions in Cranelift.

use crate::prelude::*;

#[cfg(all(feature = "jit", unix))]
#[no_mangle]
pub static mut __cg_clif_global_atomic_mutex: libc::pthread_mutex_t =
    libc::PTHREAD_MUTEX_INITIALIZER;

pub(crate) fn init_global_lock(
    module: &mut impl Module,
    bcx: &mut FunctionBuilder<'_>,
    use_jit: bool,
) {
    if use_jit {
        // When using JIT, dylibs won't find the __cg_clif_global_atomic_mutex data object defined here,
        // so instead we define it in the cg_clif dylib.

        return;
    }

    let mut data_ctx = DataContext::new();
    data_ctx.define_zeroinit(1024); // 1024 bytes should be big enough on all platforms.
    data_ctx.set_align(16);
    let atomic_mutex = module
        .declare_data(
            "__cg_clif_global_atomic_mutex",
            Linkage::Export,
            true,
            false,
        )
        .unwrap();
    module.define_data(atomic_mutex, &data_ctx).unwrap();

    let pthread_mutex_init = module
        .declare_function(
            "pthread_mutex_init",
            Linkage::Import,
            &cranelift_codegen::ir::Signature {
                call_conv: module.target_config().default_call_conv,
                params: vec![
                    AbiParam::new(
                        module.target_config().pointer_type(), /* *mut pthread_mutex_t */
                    ),
                    AbiParam::new(
                        module.target_config().pointer_type(), /* *const pthread_mutex_attr_t */
                    ),
                ],
                returns: vec![AbiParam::new(types::I32 /* c_int */)],
            },
        )
        .unwrap();

    let pthread_mutex_init = module.declare_func_in_func(pthread_mutex_init, bcx.func);

    let atomic_mutex = module.declare_data_in_func(atomic_mutex, bcx.func);
    let atomic_mutex = bcx
        .ins()
        .global_value(module.target_config().pointer_type(), atomic_mutex);

    let nullptr = bcx.ins().iconst(module.target_config().pointer_type(), 0);

    bcx.ins().call(pthread_mutex_init, &[atomic_mutex, nullptr]);
}

pub(crate) fn init_global_lock_constructor(
    module: &mut impl Module,
    constructor_name: &str,
) -> FuncId {
    let sig = Signature::new(CallConv::SystemV);
    let init_func_id = module
        .declare_function(constructor_name, Linkage::Export, &sig)
        .unwrap();

    let mut ctx = Context::new();
    ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
    {
        let mut func_ctx = FunctionBuilderContext::new();
        let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

        let block = bcx.create_block();
        bcx.switch_to_block(block);

        crate::atomic_shim::init_global_lock(module, &mut bcx, false);

        bcx.ins().return_(&[]);
        bcx.seal_all_blocks();
        bcx.finalize();
    }
    module
        .define_function(
            init_func_id,
            &mut ctx,
            &mut cranelift_codegen::binemit::NullTrapSink {},
        )
        .unwrap();

    init_func_id
}

pub(crate) fn lock_global_lock(fx: &mut FunctionCx<'_, '_, impl Module>) {
    let atomic_mutex = fx
        .cx
        .module
        .declare_data(
            "__cg_clif_global_atomic_mutex",
            Linkage::Import,
            true,
            false,
        )
        .unwrap();

    let pthread_mutex_lock = fx
        .cx
        .module
        .declare_function(
            "pthread_mutex_lock",
            Linkage::Import,
            &cranelift_codegen::ir::Signature {
                call_conv: fx.cx.module.target_config().default_call_conv,
                params: vec![AbiParam::new(
                    fx.cx.module.target_config().pointer_type(), /* *mut pthread_mutex_t */
                )],
                returns: vec![AbiParam::new(types::I32 /* c_int */)],
            },
        )
        .unwrap();

    let pthread_mutex_lock = fx
        .cx
        .module
        .declare_func_in_func(pthread_mutex_lock, fx.bcx.func);

    let atomic_mutex = fx.cx.module.declare_data_in_func(atomic_mutex, fx.bcx.func);
    let atomic_mutex = fx
        .bcx
        .ins()
        .global_value(fx.cx.module.target_config().pointer_type(), atomic_mutex);

    fx.bcx.ins().call(pthread_mutex_lock, &[atomic_mutex]);
}

pub(crate) fn unlock_global_lock(fx: &mut FunctionCx<'_, '_, impl Module>) {
    let atomic_mutex = fx
        .cx
        .module
        .declare_data(
            "__cg_clif_global_atomic_mutex",
            Linkage::Import,
            true,
            false,
        )
        .unwrap();

    let pthread_mutex_unlock = fx
        .cx
        .module
        .declare_function(
            "pthread_mutex_unlock",
            Linkage::Import,
            &cranelift_codegen::ir::Signature {
                call_conv: fx.cx.module.target_config().default_call_conv,
                params: vec![AbiParam::new(
                    fx.cx.module.target_config().pointer_type(), /* *mut pthread_mutex_t */
                )],
                returns: vec![AbiParam::new(types::I32 /* c_int */)],
            },
        )
        .unwrap();

    let pthread_mutex_unlock = fx
        .cx
        .module
        .declare_func_in_func(pthread_mutex_unlock, fx.bcx.func);

    let atomic_mutex = fx.cx.module.declare_data_in_func(atomic_mutex, fx.bcx.func);
    let atomic_mutex = fx
        .bcx
        .ins()
        .global_value(fx.cx.module.target_config().pointer_type(), atomic_mutex);

    fx.bcx.ins().call(pthread_mutex_unlock, &[atomic_mutex]);
}
<|endoftext|>


<commit_before>#[cfg(feature = "serialize")]
use serde::ser::{Serialize, SerializeStruct, Serializer};
use std::error;
use std::error::Error;
use std::fmt;
use std::net::AddrParseError;
use std::num::ParseFloatError;
use std::num::ParseIntError;

#[derive(Debug)]
pub enum SdpParserInternalError {
    Generic(String),
    Unsupported(String),
    Integer(ParseIntError),
    Float(ParseFloatError),
    Address(AddrParseError),
}

impl fmt::Display for SdpParserInternalError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdpParserInternalError::Generic(ref message) => {
                write!(f, "Generic parsing error: {}", message)
            }
            SdpParserInternalError::Unsupported(ref message) => {
                write!(f, "Unsupported parsing error: {}", message)
            }
            SdpParserInternalError::Integer(ref error) => {
                write!(f, "Integer parsing error: {}", error.description())
            }
            SdpParserInternalError::Float(ref error) => {
                write!(f, "Float parsing error: {}", error.description())
            }
            SdpParserInternalError::Address(ref error) => {
                write!(f, "IP address parsing error: {}", error.description())
            }
        }
    }
}

impl error::Error for SdpParserInternalError {
    fn description(&self) -> &str {
        match *self {
            SdpParserInternalError::Generic(ref message)
            | SdpParserInternalError::Unsupported(ref message) => message,
            SdpParserInternalError::Integer(ref error) => error.description(),
            SdpParserInternalError::Float(ref error) => error.description(),
            SdpParserInternalError::Address(ref error) => error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SdpParserInternalError::Integer(ref error) => Some(error),
            SdpParserInternalError::Float(ref error) => Some(error),
            SdpParserInternalError::Address(ref error) => Some(error),
            // Can't tell much more about our internal errors
            _ => None,
        }
    }
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_generic() {
    let generic = SdpParserInternalError::Generic("generic message".to_string());
    assert_eq!(
        format!("{}", generic),
        "Generic parsing error: generic message"
    );
    assert_eq!(generic.description(), "generic message");
    assert!(generic.cause().is_none());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_unsupported() {
    let unsupported =
        SdpParserInternalError::Unsupported("unsupported internal message".to_string());
    assert_eq!(
        format!("{}", unsupported),
        "Unsupported parsing error: unsupported internal message"
    );
    assert_eq!(unsupported.description(), "unsupported internal message");
    assert!(unsupported.cause().is_none());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_integer() {
    let v = "12a";
    let integer = v.parse::<u64>();
    assert!(integer.is_err());
    let int_err = SdpParserInternalError::Integer(integer.err().unwrap());
    assert_eq!(
        format!("{}", int_err),
        "Integer parsing error: invalid digit found in string"
    );
    assert_eq!(int_err.description(), "invalid digit found in string");
    assert!(!int_err.cause().is_none());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_float() {
    let v = "12.2a";
    let float = v.parse::<f32>();
    assert!(float.is_err());
    let int_err = SdpParserInternalError::Float(float.err().unwrap());
    assert_eq!(
        format!("{}", int_err),
        "Float parsing error: invalid float literal"
    );
    assert_eq!(int_err.description(), "invalid float literal");
    assert!(!int_err.cause().is_none());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_address() {
    let v = "127.0.0.a";
    use std::net::IpAddr;
    use std::str::FromStr;
    let addr = IpAddr::from_str(v);
    assert!(addr.is_err());
    let addr_err = SdpParserInternalError::Address(addr.err().unwrap());
    assert_eq!(
        format!("{}", addr_err),
        "IP address parsing error: invalid IP address syntax"
    );
    assert_eq!(addr_err.description(), "invalid IP address syntax");
    assert!(!addr_err.cause().is_none());
}

#[derive(Debug)]
pub enum SdpParserError {
    Line {
        error: SdpParserInternalError,
        line: String,
        line_number: usize,
    },
    Unsupported {
        error: SdpParserInternalError,
        line: String,
        line_number: usize,
    },
    Sequence {
        message: String,
        line_number: usize,
    },
}

#[cfg(feature = "serialize")]
impl Serialize for SdpParserError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state = serializer.serialize_struct(
            "error",
            match *self {
                SdpParserError::Sequence { .. } => 3,
                _ => 4,
            },
        )?;
        match *self {
            SdpParserError::Line {
                ref error,
                ref line,
                ..
            } => {
                state.serialize_field("type", "Line")?;
                state.serialize_field("message", &format!("{}", error))?;
                state.serialize_field("line", &line)?
            }
            SdpParserError::Unsupported {
                ref error,
                ref line,
                ..
            } => {
                state.serialize_field("type", "Unsupported")?;
                state.serialize_field("message", &format!("{}", error))?;
                state.serialize_field("line", &line)?
            }
            SdpParserError::Sequence { ref message, .. } => {
                state.serialize_field("type", "Sequence")?;
                state.serialize_field("message", &message)?;
            }
        };
        state.serialize_field(
            "line_number",
            &match *self {
                SdpParserError::Line { line_number, .. } => line_number,
                SdpParserError::Unsupported { line_number, .. } => line_number,
                SdpParserError::Sequence { line_number, .. } => line_number,
            },
        )?;
        state.end()
    }
}

impl fmt::Display for SdpParserError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdpParserError::Line {
                ref error,
                ref line,
                ref line_number,
            } => write!(
                f,
                "Line error: {} in line({}): {}",
                error.description(),
                line_number,
                line
            ),
            SdpParserError::Unsupported {
                ref error,
                ref line,
                ref line_number,
            } => write!(
                f,
                "Unsupported: {} in line({}): {}",
                error.description(),
                line_number,
                line
            ),
            SdpParserError::Sequence {
                ref message,
                ref line_number,
            } => write!(f, "Sequence error in line({}): {}", line_number, message),
        }
    }
}

impl error::Error for SdpParserError {
    fn description(&self) -> &str {
        match *self {
            SdpParserError::Line { ref error, .. }
            | SdpParserError::Unsupported { ref error, .. } => error.description(),
            SdpParserError::Sequence { ref message, .. } => message,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SdpParserError::Line { ref error, .. }
            | SdpParserError::Unsupported { ref error, .. } => Some(error),
            // Can't tell much more about our internal errors
            _ => None,
        }
    }
}

impl From<ParseIntError> for SdpParserInternalError {
    fn from(err: ParseIntError) -> SdpParserInternalError {
        SdpParserInternalError::Integer(err)
    }
}

impl From<AddrParseError> for SdpParserInternalError {
    fn from(err: AddrParseError) -> SdpParserInternalError {
        SdpParserInternalError::Address(err)
    }
}

impl From<ParseFloatError> for SdpParserInternalError {
    fn from(err: ParseFloatError) -> SdpParserInternalError {
        SdpParserInternalError::Float(err)
    }
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_error_line() {
    let line1 = SdpParserError::Line {
        error: SdpParserInternalError::Generic("test message".to_string()),
        line: "test line".to_string(),
        line_number: 13,
    };
    assert_eq!(
        format!("{}", line1),
        "Line error: test message in line(13): test line"
    );
    assert_eq!(line1.description(), "test message");
    assert!(line1.cause().is_some());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_error_unsupported() {
    let unsupported1 = SdpParserError::Unsupported {
        error: SdpParserInternalError::Generic("unsupported value".to_string()),
        line: "unsupported line".to_string(),
        line_number: 21,
    };
    assert_eq!(
        format!("{}", unsupported1),
        "Unsupported: unsupported value in line(21): unsupported line"
    );
    assert_eq!(unsupported1.description(), "unsupported value");
    assert!(unsupported1.cause().is_some());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_error_sequence() {
    let sequence1 = SdpParserError::Sequence {
        message: "sequence message".to_string(),
        line_number: 42,
    };
    assert_eq!(
        format!("{}", sequence1),
        "Sequence error in line(42): sequence message"
    );
    assert_eq!(sequence1.description(), "sequence message");
    assert!(sequence1.cause().is_none());
}
<commit_msg>Add dyn to error::Error impl function cause<commit_after>#[cfg(feature = "serialize")]
use serde::ser::{Serialize, SerializeStruct, Serializer};
use std::error;
use std::error::Error;
use std::fmt;
use std::net::AddrParseError;
use std::num::ParseFloatError;
use std::num::ParseIntError;

#[derive(Debug)]
pub enum SdpParserInternalError {
    Generic(String),
    Unsupported(String),
    Integer(ParseIntError),
    Float(ParseFloatError),
    Address(AddrParseError),
}

impl fmt::Display for SdpParserInternalError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdpParserInternalError::Generic(ref message) => {
                write!(f, "Generic parsing error: {}", message)
            }
            SdpParserInternalError::Unsupported(ref message) => {
                write!(f, "Unsupported parsing error: {}", message)
            }
            SdpParserInternalError::Integer(ref error) => {
                write!(f, "Integer parsing error: {}", error.description())
            }
            SdpParserInternalError::Float(ref error) => {
                write!(f, "Float parsing error: {}", error.description())
            }
            SdpParserInternalError::Address(ref error) => {
                write!(f, "IP address parsing error: {}", error.description())
            }
        }
    }
}

impl error::Error for SdpParserInternalError {
    fn description(&self) -> &str {
        match *self {
            SdpParserInternalError::Generic(ref message)
            | SdpParserInternalError::Unsupported(ref message) => message,
            SdpParserInternalError::Integer(ref error) => error.description(),
            SdpParserInternalError::Float(ref error) => error.description(),
            SdpParserInternalError::Address(ref error) => error.description(),
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            SdpParserInternalError::Integer(ref error) => Some(error),
            SdpParserInternalError::Float(ref error) => Some(error),
            SdpParserInternalError::Address(ref error) => Some(error),
            // Can't tell much more about our internal errors
            _ => None,
        }
    }
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_generic() {
    let generic = SdpParserInternalError::Generic("generic message".to_string());
    assert_eq!(
        format!("{}", generic),
        "Generic parsing error: generic message"
    );
    assert_eq!(generic.description(), "generic message");
    assert!(generic.cause().is_none());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_unsupported() {
    let unsupported =
        SdpParserInternalError::Unsupported("unsupported internal message".to_string());
    assert_eq!(
        format!("{}", unsupported),
        "Unsupported parsing error: unsupported internal message"
    );
    assert_eq!(unsupported.description(), "unsupported internal message");
    assert!(unsupported.cause().is_none());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_integer() {
    let v = "12a";
    let integer = v.parse::<u64>();
    assert!(integer.is_err());
    let int_err = SdpParserInternalError::Integer(integer.err().unwrap());
    assert_eq!(
        format!("{}", int_err),
        "Integer parsing error: invalid digit found in string"
    );
    assert_eq!(int_err.description(), "invalid digit found in string");
    assert!(!int_err.cause().is_none());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_float() {
    let v = "12.2a";
    let float = v.parse::<f32>();
    assert!(float.is_err());
    let int_err = SdpParserInternalError::Float(float.err().unwrap());
    assert_eq!(
        format!("{}", int_err),
        "Float parsing error: invalid float literal"
    );
    assert_eq!(int_err.description(), "invalid float literal");
    assert!(!int_err.cause().is_none());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_internal_error_address() {
    let v = "127.0.0.a";
    use std::net::IpAddr;
    use std::str::FromStr;
    let addr = IpAddr::from_str(v);
    assert!(addr.is_err());
    let addr_err = SdpParserInternalError::Address(addr.err().unwrap());
    assert_eq!(
        format!("{}", addr_err),
        "IP address parsing error: invalid IP address syntax"
    );
    assert_eq!(addr_err.description(), "invalid IP address syntax");
    assert!(!addr_err.cause().is_none());
}

#[derive(Debug)]
pub enum SdpParserError {
    Line {
        error: SdpParserInternalError,
        line: String,
        line_number: usize,
    },
    Unsupported {
        error: SdpParserInternalError,
        line: String,
        line_number: usize,
    },
    Sequence {
        message: String,
        line_number: usize,
    },
}

#[cfg(feature = "serialize")]
impl Serialize for SdpParserError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state = serializer.serialize_struct(
            "error",
            match *self {
                SdpParserError::Sequence { .. } => 3,
                _ => 4,
            },
        )?;
        match *self {
            SdpParserError::Line {
                ref error,
                ref line,
                ..
            } => {
                state.serialize_field("type", "Line")?;
                state.serialize_field("message", &format!("{}", error))?;
                state.serialize_field("line", &line)?
            }
            SdpParserError::Unsupported {
                ref error,
                ref line,
                ..
            } => {
                state.serialize_field("type", "Unsupported")?;
                state.serialize_field("message", &format!("{}", error))?;
                state.serialize_field("line", &line)?
            }
            SdpParserError::Sequence { ref message, .. } => {
                state.serialize_field("type", "Sequence")?;
                state.serialize_field("message", &message)?;
            }
        };
        state.serialize_field(
            "line_number",
            &match *self {
                SdpParserError::Line { line_number, .. } => line_number,
                SdpParserError::Unsupported { line_number, .. } => line_number,
                SdpParserError::Sequence { line_number, .. } => line_number,
            },
        )?;
        state.end()
    }
}

impl fmt::Display for SdpParserError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdpParserError::Line {
                ref error,
                ref line,
                ref line_number,
            } => write!(
                f,
                "Line error: {} in line({}): {}",
                error.description(),
                line_number,
                line
            ),
            SdpParserError::Unsupported {
                ref error,
                ref line,
                ref line_number,
            } => write!(
                f,
                "Unsupported: {} in line({}): {}",
                error.description(),
                line_number,
                line
            ),
            SdpParserError::Sequence {
                ref message,
                ref line_number,
            } => write!(f, "Sequence error in line({}): {}", line_number, message),
        }
    }
}

impl error::Error for SdpParserError {
    fn description(&self) -> &str {
        match *self {
            SdpParserError::Line { ref error, .. }
            | SdpParserError::Unsupported { ref error, .. } => error.description(),
            SdpParserError::Sequence { ref message, .. } => message,
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            SdpParserError::Line { ref error, .. }
            | SdpParserError::Unsupported { ref error, .. } => Some(error),
            // Can't tell much more about our internal errors
            _ => None,
        }
    }
}

impl From<ParseIntError> for SdpParserInternalError {
    fn from(err: ParseIntError) -> SdpParserInternalError {
        SdpParserInternalError::Integer(err)
    }
}

impl From<AddrParseError> for SdpParserInternalError {
    fn from(err: AddrParseError) -> SdpParserInternalError {
        SdpParserInternalError::Address(err)
    }
}

impl From<ParseFloatError> for SdpParserInternalError {
    fn from(err: ParseFloatError) -> SdpParserInternalError {
        SdpParserInternalError::Float(err)
    }
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_error_line() {
    let line1 = SdpParserError::Line {
        error: SdpParserInternalError::Generic("test message".to_string()),
        line: "test line".to_string(),
        line_number: 13,
    };
    assert_eq!(
        format!("{}", line1),
        "Line error: test message in line(13): test line"
    );
    assert_eq!(line1.description(), "test message");
    assert!(line1.cause().is_some());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_error_unsupported() {
    let unsupported1 = SdpParserError::Unsupported {
        error: SdpParserInternalError::Generic("unsupported value".to_string()),
        line: "unsupported line".to_string(),
        line_number: 21,
    };
    assert_eq!(
        format!("{}", unsupported1),
        "Unsupported: unsupported value in line(21): unsupported line"
    );
    assert_eq!(unsupported1.description(), "unsupported value");
    assert!(unsupported1.cause().is_some());
}

#[test]
#[allow(deprecated)] // see issue #102
fn test_sdp_parser_error_sequence() {
    let sequence1 = SdpParserError::Sequence {
        message: "sequence message".to_string(),
        line_number: 42,
    };
    assert_eq!(
        format!("{}", sequence1),
        "Sequence error in line(42): sequence message"
    );
    assert_eq!(sequence1.description(), "sequence message");
    assert!(sequence1.cause().is_none());
}
<|endoftext|>


<commit_before>use base64::DecodeError;
use crypto_mac::MacError;
use serde_json::Error as JsonError;
use std::fmt;
use std::string::FromUtf8Error;

#[derive(Debug)]
pub enum Error {
    Format,
    Base64(DecodeError),
    Json(JsonError),
    Utf8(FromUtf8Error),
    RustCryptoMac(MacError),
    #[cfg(feature = "openssl")]
    OpenSsl(openssl::error::ErrorStack),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::Format => write!(f, "Format"),
            Error::Base64(ref x) => write!(f, "{}", x),
            Error::Json(ref x) => write!(f, "{}", x),
            Error::Utf8(ref x) => write!(f, "{}", x),
            Error::RustCryptoMac(ref x) => write!(f, "{}", x),
            #[cfg(feature = "openssl")]
            Error::OpenSsl(ref x) => write!(f, "{}", x),
        }
    }
}

macro_rules! error_wrap {
    ($f: ty, $e: expr) => {
        impl From<$f> for Error {
            fn from(f: $f) -> Error {
                $e(f)
            }
        }
    };
}

error_wrap!(DecodeError, Error::Base64);
error_wrap!(JsonError, Error::Json);
error_wrap!(FromUtf8Error, Error::Utf8);
error_wrap!(MacError, Error::RustCryptoMac);
#[cfg(feature = "openssl")]
error_wrap!(openssl::error::ErrorStack, Error::OpenSsl);
<commit_msg>Add algorithm mismatch error type<commit_after>use base64::DecodeError;
use crypto_mac::MacError;
use serde_json::Error as JsonError;
use std::fmt;
use std::string::FromUtf8Error;
use crate::algorithm::AlgorithmType;

#[derive(Debug)]
pub enum Error {
    AlgorithmMismatch(AlgorithmType, AlgorithmType),
    Format,
    Base64(DecodeError),
    Json(JsonError),
    Utf8(FromUtf8Error),
    RustCryptoMac(MacError),
    #[cfg(feature = "openssl")]
    OpenSsl(openssl::error::ErrorStack),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::AlgorithmMismatch(a, b) =>
                write!(f, "Expected algorithm type {:?} but found {:?}", a, b),
            Error::Format => write!(f, "Format"),
            Error::Base64(ref x) => write!(f, "{}", x),
            Error::Json(ref x) => write!(f, "{}", x),
            Error::Utf8(ref x) => write!(f, "{}", x),
            Error::RustCryptoMac(ref x) => write!(f, "{}", x),
            #[cfg(feature = "openssl")]
            Error::OpenSsl(ref x) => write!(f, "{}", x),
        }
    }
}

macro_rules! error_wrap {
    ($f: ty, $e: expr) => {
        impl From<$f> for Error {
            fn from(f: $f) -> Error {
                $e(f)
            }
        }
    };
}

error_wrap!(DecodeError, Error::Base64);
error_wrap!(JsonError, Error::Json);
error_wrap!(FromUtf8Error, Error::Utf8);
error_wrap!(MacError, Error::RustCryptoMac);
#[cfg(feature = "openssl")]
error_wrap!(openssl::error::ErrorStack, Error::OpenSsl);
<|endoftext|>


<commit_before>//! Error types and conversions.

use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt::Error as FmtError;
use std::io::Error as IoError;
use std::string::FromUtf8Error;
use std::sync::PoisonError;

use argon2rs::verifier::DecodeError;
use base64::Base64Error;
use diesel::result::{TransactionError, Error as DieselError};
use iron::{IronError, Response};
use iron::modifier::Modifier;
use iron::status::Status;
use macaroons::error::Error as MacaroonsError;
use persistent::PersistentError;
use r2d2::GetTimeout;
use ruma_identifiers::Error as RumaIdentifiersError;
use serde::ser::{Serialize, Serializer};
use serde_json::{Error as SerdeJsonError, to_string};

/// A client-facing error.
#[derive(Clone, Debug, Serialize)]
pub struct ApiError {
    errcode: ApiErrorCode,
    error: String,
}

/// The error code for a client-facing error.
#[derive(Clone, Debug)]
pub enum ApiErrorCode {
    /// Request contained an event that was not valid input for the requested API.
    BadEvent,
    /// The request contained valid JSON, but it was malformed in some way,
    /// e.g. missing required keys, invalid values for keys.
    BadJson,
    /// Forbidden access, e.g. joining a room without permission, failed login.
    Forbidden,
    /// Guests are not allowed to perform the requested operation.
    GuestAccessForbidden,
    /// Too many requests have been sent in a short period of time. Wait a while then try again.
    LimitExceeded,
    /// A required input parameter was not supplied, e.g. query string or URL path-based parameter.
    MissingParam,
    /// No resource was found for this request.
    NotFound,
    /// Request did not contain valid JSON.
    NotJson,
    /// Ruma does not implement the requested API.
    Unimplemented,
    /// Errors not fitting into another category.
    Unknown,
    /// The access token specified was not recognised.
    UnknownToken,
}

/// An operator-facing error.
pub struct CliError {
    error: String,
}

/// Extensions for `Result` to making handling Ruma API errors easier.
pub trait MapApiError {
    type Output;
    type Error: Debug;

    /// Similar to `map_err`, but prints the original error to the debug log and must always
    /// return an `ApiError`.
    fn map_api_err<O>(self, op: O) -> Result<Self::Output, ApiError>
    where O: FnOnce(Self::Error) -> ApiError;
}

impl ApiError {
    /// Create an error for invalid or incomplete input to event creation API endpoints.
    pub fn bad_event(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::BadEvent,
            error: message.unwrap_or("Invalid event data.").to_string(),
        }
    }

    /// Create an error for invalid or incomplete JSON in request bodies.
    pub fn bad_json(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::BadJson,
            error: message.unwrap_or("Invalid or missing key-value pairs in JSON.").to_string(),
        }
    }

    /// Create an error for endpoints where guest accounts are not supported.
    pub fn guest_forbidden(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::GuestAccessForbidden,
            error: message.unwrap_or("Guest accounts are forbidden.").to_string(),
        }
    }

    /// Create an error for requests missing a value for a required parameter.
    pub fn missing_param(param_name: &str) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::MissingParam,
            error: format!("Missing value for required parameter: {}.", param_name),
        }
    }

    /// Create an error for requests that do not map to a resource.
    pub fn not_found(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::NotFound,
            error: message.unwrap_or("No resource was found for this request.").to_string(),
        }
    }

    /// Create an error for requests without JSON bodies.
    pub fn not_json(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::NotJson,
            error: message.unwrap_or("No JSON found in request body.").to_string(),
        }
    }

    /// Create an error for requests that are not marked as containing JSON.
    pub fn wrong_content_type(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::NotJson,
            error: message.unwrap_or(
                "Request's Content-Type header must be application/json."
            ).to_string(),
        }
    }

    /// Create an error for requests that did not provide required authentication parameters.
    pub fn unauthorized(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::Forbidden,
            error: message.unwrap_or("Authentication is required.").to_string(),
        }
    }

    /// Create an error for Matrix APIs that Ruma intentionally does not implement.
    pub fn unimplemented(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::Unimplemented,
            error: message.unwrap_or("The homeserver does not implement this API.").to_string(),
        }
    }

    /// Create a generic error for anything not specifically covered by the Matrix spec.
    pub fn unknown(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::Unknown,
            error: message.unwrap_or("An unknown server-side error occurred.").to_string(),
        }
    }
}

impl Display for ApiError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.error)
    }
}

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

impl From<IoError> for ApiError {
    fn from(error: IoError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<DecodeError> for ApiError {
    fn from(error: DecodeError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<Base64Error> for ApiError {
    fn from(error: Base64Error) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<DieselError> for ApiError {
    fn from(error: DieselError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl<T> From<TransactionError<T>> for ApiError where T: Error {
    fn from(error: TransactionError<T>) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<MacaroonsError> for ApiError {
    fn from(error: MacaroonsError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<PersistentError> for ApiError {
    fn from(error: PersistentError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<RumaIdentifiersError> for ApiError {
    fn from(error: RumaIdentifiersError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<GetTimeout> for ApiError {
    fn from(error: GetTimeout) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<FromUtf8Error> for ApiError {
    fn from(error: FromUtf8Error) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl<T> From<PoisonError<T>> for ApiError {
    fn from(error: PoisonError<T>) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<SerdeJsonError> for ApiError {
    fn from(error: SerdeJsonError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<ApiError> for IronError {
    fn from(error: ApiError) -> IronError {
        IronError::new(error.clone(), error)
    }
}

impl Modifier<Response> for ApiError {
    fn modify(self, response: &mut Response) {
        response.status = Some(self.errcode.status_code());
        response.body = Some(Box::new(to_string(&self).expect("ApiError should always serialize")));
    }
}

impl ApiErrorCode {
    /// The HTTP status code that should be used to represent the `ApiErrorCode`.
    pub fn status_code(&self) -> Status {
        match *self {
            ApiErrorCode::BadEvent => Status::UnprocessableEntity,
            ApiErrorCode::BadJson => Status::UnprocessableEntity,
            ApiErrorCode::Forbidden => Status::Forbidden,
            ApiErrorCode::GuestAccessForbidden => Status::Forbidden,
            ApiErrorCode::LimitExceeded => Status::TooManyRequests,
            ApiErrorCode::MissingParam => Status::BadRequest,
            ApiErrorCode::NotFound => Status::NotFound,
            ApiErrorCode::NotJson => Status::BadRequest,
            ApiErrorCode::Unimplemented => Status::NotFound,
            ApiErrorCode::Unknown => Status::InternalServerError,
            ApiErrorCode::UnknownToken => Status::Unauthorized,
        }
    }
}

impl Serialize for ApiErrorCode {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let value = match *self {
            ApiErrorCode::BadEvent => "IO.RUMA_BAD_EVENT",
            ApiErrorCode::BadJson => "M_BAD_JSON",
            ApiErrorCode::Forbidden => "M_FORBIDDEN",
            ApiErrorCode::GuestAccessForbidden => "M_GUEST_ACCESS_FORBIDDEN",
            ApiErrorCode::LimitExceeded => "M_LIMIT_EXCEEDED",
            ApiErrorCode::MissingParam => "M_MISSING_PARAM",
            ApiErrorCode::NotFound => "M_NOT_FOUND",
            ApiErrorCode::NotJson => "M_NOT_JSON",
            ApiErrorCode::Unimplemented => "IO.RUMA_UNIMPLEMENTED",
            ApiErrorCode::Unknown => "M_UNKNOWN",
            ApiErrorCode::UnknownToken => "M_UNKNOWN_TOKEN",
        };

        serializer.serialize_str(value)
    }
}

impl CliError {
    /// Create a new `CliError` from any `Error` type.
    pub fn new<E>(error: E) -> CliError where E: Into<String> {
        CliError {
            error: error.into(),
        }
    }
}

impl<E> From<E> for CliError where E: Error {
    fn from(error: E) -> CliError {
        CliError::new(error.description())
    }
}

impl Display for CliError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.error)
    }
}

impl<T, E> MapApiError for Result<T, E> where E: Debug {
    type Output = T;
    type Error = E;

    #[inline]
    fn map_api_err<O>(self, op: O) -> Result<T, ApiError> where O: FnOnce(E) -> ApiError {
        match self {
            Ok(t) => Ok(t),
            Err(e) => {
                debug!("Converting to ApiError from: {:?}", e);

                Err(op(e))
            }
        }
    }
}
<commit_msg>Add missing docs for MapApiError's associated types.<commit_after>//! Error types and conversions.

use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt::Error as FmtError;
use std::io::Error as IoError;
use std::string::FromUtf8Error;
use std::sync::PoisonError;

use argon2rs::verifier::DecodeError;
use base64::Base64Error;
use diesel::result::{TransactionError, Error as DieselError};
use iron::{IronError, Response};
use iron::modifier::Modifier;
use iron::status::Status;
use macaroons::error::Error as MacaroonsError;
use persistent::PersistentError;
use r2d2::GetTimeout;
use ruma_identifiers::Error as RumaIdentifiersError;
use serde::ser::{Serialize, Serializer};
use serde_json::{Error as SerdeJsonError, to_string};

/// A client-facing error.
#[derive(Clone, Debug, Serialize)]
pub struct ApiError {
    errcode: ApiErrorCode,
    error: String,
}

/// The error code for a client-facing error.
#[derive(Clone, Debug)]
pub enum ApiErrorCode {
    /// Request contained an event that was not valid input for the requested API.
    BadEvent,
    /// The request contained valid JSON, but it was malformed in some way,
    /// e.g. missing required keys, invalid values for keys.
    BadJson,
    /// Forbidden access, e.g. joining a room without permission, failed login.
    Forbidden,
    /// Guests are not allowed to perform the requested operation.
    GuestAccessForbidden,
    /// Too many requests have been sent in a short period of time. Wait a while then try again.
    LimitExceeded,
    /// A required input parameter was not supplied, e.g. query string or URL path-based parameter.
    MissingParam,
    /// No resource was found for this request.
    NotFound,
    /// Request did not contain valid JSON.
    NotJson,
    /// Ruma does not implement the requested API.
    Unimplemented,
    /// Errors not fitting into another category.
    Unknown,
    /// The access token specified was not recognised.
    UnknownToken,
}

/// An operator-facing error.
pub struct CliError {
    error: String,
}

/// Extensions for `Result` to make handling Ruma API errors easier.
pub trait MapApiError {
    /// The type contained in a successful result.
    type Output;
    /// The initial error type contained in an unsuccessful result.
    ///
    /// This will be converted to `ApiError`.
    type Error: Debug;

    /// Similar to `map_err`, but prints the original error to the debug log and must always
    /// return an `ApiError`.
    fn map_api_err<O>(self, op: O) -> Result<Self::Output, ApiError>
    where O: FnOnce(Self::Error) -> ApiError;
}

impl ApiError {
    /// Create an error for invalid or incomplete input to event creation API endpoints.
    pub fn bad_event(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::BadEvent,
            error: message.unwrap_or("Invalid event data.").to_string(),
        }
    }

    /// Create an error for invalid or incomplete JSON in request bodies.
    pub fn bad_json(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::BadJson,
            error: message.unwrap_or("Invalid or missing key-value pairs in JSON.").to_string(),
        }
    }

    /// Create an error for endpoints where guest accounts are not supported.
    pub fn guest_forbidden(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::GuestAccessForbidden,
            error: message.unwrap_or("Guest accounts are forbidden.").to_string(),
        }
    }

    /// Create an error for requests missing a value for a required parameter.
    pub fn missing_param(param_name: &str) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::MissingParam,
            error: format!("Missing value for required parameter: {}.", param_name),
        }
    }

    /// Create an error for requests that do not map to a resource.
    pub fn not_found(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::NotFound,
            error: message.unwrap_or("No resource was found for this request.").to_string(),
        }
    }

    /// Create an error for requests without JSON bodies.
    pub fn not_json(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::NotJson,
            error: message.unwrap_or("No JSON found in request body.").to_string(),
        }
    }

    /// Create an error for requests that are not marked as containing JSON.
    pub fn wrong_content_type(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::NotJson,
            error: message.unwrap_or(
                "Request's Content-Type header must be application/json."
            ).to_string(),
        }
    }

    /// Create an error for requests that did not provide required authentication parameters.
    pub fn unauthorized(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::Forbidden,
            error: message.unwrap_or("Authentication is required.").to_string(),
        }
    }

    /// Create an error for Matrix APIs that Ruma intentionally does not implement.
    pub fn unimplemented(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::Unimplemented,
            error: message.unwrap_or("The homeserver does not implement this API.").to_string(),
        }
    }

    /// Create a generic error for anything not specifically covered by the Matrix spec.
    pub fn unknown(message: Option<&str>) -> ApiError {
        ApiError {
            errcode: ApiErrorCode::Unknown,
            error: message.unwrap_or("An unknown server-side error occurred.").to_string(),
        }
    }
}

impl Display for ApiError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.error)
    }
}

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

impl From<IoError> for ApiError {
    fn from(error: IoError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<DecodeError> for ApiError {
    fn from(error: DecodeError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<Base64Error> for ApiError {
    fn from(error: Base64Error) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<DieselError> for ApiError {
    fn from(error: DieselError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl<T> From<TransactionError<T>> for ApiError where T: Error {
    fn from(error: TransactionError<T>) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<MacaroonsError> for ApiError {
    fn from(error: MacaroonsError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<PersistentError> for ApiError {
    fn from(error: PersistentError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<RumaIdentifiersError> for ApiError {
    fn from(error: RumaIdentifiersError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<GetTimeout> for ApiError {
    fn from(error: GetTimeout) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<FromUtf8Error> for ApiError {
    fn from(error: FromUtf8Error) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl<T> From<PoisonError<T>> for ApiError {
    fn from(error: PoisonError<T>) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<SerdeJsonError> for ApiError {
    fn from(error: SerdeJsonError) -> ApiError {
        debug!("Converting to ApiError from: {:?}", error);

        ApiError::unknown(None)
    }
}

impl From<ApiError> for IronError {
    fn from(error: ApiError) -> IronError {
        IronError::new(error.clone(), error)
    }
}

impl Modifier<Response> for ApiError {
    fn modify(self, response: &mut Response) {
        response.status = Some(self.errcode.status_code());
        response.body = Some(Box::new(to_string(&self).expect("ApiError should always serialize")));
    }
}

impl ApiErrorCode {
    /// The HTTP status code that should be used to represent the `ApiErrorCode`.
    pub fn status_code(&self) -> Status {
        match *self {
            ApiErrorCode::BadEvent => Status::UnprocessableEntity,
            ApiErrorCode::BadJson => Status::UnprocessableEntity,
            ApiErrorCode::Forbidden => Status::Forbidden,
            ApiErrorCode::GuestAccessForbidden => Status::Forbidden,
            ApiErrorCode::LimitExceeded => Status::TooManyRequests,
            ApiErrorCode::MissingParam => Status::BadRequest,
            ApiErrorCode::NotFound => Status::NotFound,
            ApiErrorCode::NotJson => Status::BadRequest,
            ApiErrorCode::Unimplemented => Status::NotFound,
            ApiErrorCode::Unknown => Status::InternalServerError,
            ApiErrorCode::UnknownToken => Status::Unauthorized,
        }
    }
}

impl Serialize for ApiErrorCode {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let value = match *self {
            ApiErrorCode::BadEvent => "IO.RUMA_BAD_EVENT",
            ApiErrorCode::BadJson => "M_BAD_JSON",
            ApiErrorCode::Forbidden => "M_FORBIDDEN",
            ApiErrorCode::GuestAccessForbidden => "M_GUEST_ACCESS_FORBIDDEN",
            ApiErrorCode::LimitExceeded => "M_LIMIT_EXCEEDED",
            ApiErrorCode::MissingParam => "M_MISSING_PARAM",
            ApiErrorCode::NotFound => "M_NOT_FOUND",
            ApiErrorCode::NotJson => "M_NOT_JSON",
            ApiErrorCode::Unimplemented => "IO.RUMA_UNIMPLEMENTED",
            ApiErrorCode::Unknown => "M_UNKNOWN",
            ApiErrorCode::UnknownToken => "M_UNKNOWN_TOKEN",
        };

        serializer.serialize_str(value)
    }
}

impl CliError {
    /// Create a new `CliError` from any `Error` type.
    pub fn new<E>(error: E) -> CliError where E: Into<String> {
        CliError {
            error: error.into(),
        }
    }
}

impl<E> From<E> for CliError where E: Error {
    fn from(error: E) -> CliError {
        CliError::new(error.description())
    }
}

impl Display for CliError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.error)
    }
}

impl<T, E> MapApiError for Result<T, E> where E: Debug {
    type Output = T;
    type Error = E;

    #[inline]
    fn map_api_err<O>(self, op: O) -> Result<T, ApiError> where O: FnOnce(E) -> ApiError {
        match self {
            Ok(t) => Ok(t),
            Err(e) => {
                debug!("Converting to ApiError from: {:?}", e);

                Err(op(e))
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Our custom error types.

use std::io;

use byteorder;

#[derive(Debug)]
pub enum SdcError {
    Byteorder(byteorder::Error),
    Io(io::Error),
}

impl From<byteorder::Error> for SdcError {
    fn from(err: byteorder::Error) -> SdcError {
        SdcError::Byteorder(err)
    }
}

impl From<io::Error> for SdcError {
    fn from(err: io::Error) -> SdcError {
        SdcError::Io(err)
    }
}
<commit_msg>Implement Error for SdcError<commit_after>//! Our custom error types.

use std::error::Error;
use std::fmt;
use std::io;

use byteorder;

#[derive(Debug)]
pub enum SdcError {
    Byteorder(byteorder::Error),
    Io(io::Error),
}

impl Error for SdcError {
    fn description(&self) -> &str {
        match *self {
            SdcError::Byteorder(ref err) => err.description(),
            SdcError::Io(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            SdcError::Byteorder(ref err) => Some(err),
            SdcError::Io(ref err) => Some(err),
        }
    }
}

impl fmt::Display for SdcError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SdcError::Byteorder(ref err) => write!(f, "Byteorder error: {}", err),
            SdcError::Io(ref err) => write!(f, "IO error: {}", err),
        }
    }
}

impl From<byteorder::Error> for SdcError {
    fn from(err: byteorder::Error) -> SdcError {
        SdcError::Byteorder(err)
    }
}

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


<commit_before>//! When serializing or deserializing JSON goes wrong.

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

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::ControlCharacterWhileParsingString
            | 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.
    ///
    /// ```edition2018
    /// 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),
            }
        }
    }
}

struct ErrorImpl {
    code: ErrorCode,
    line: usize,
    column: usize,
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
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,

    /// Control character found while parsing a string.
    ControlCharacterWhileParsingString,

    /// 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)]
    #[cold]
    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).
    //
    // Update `eager_json` crate when this function changes.
    #[doc(hidden)]
    #[cold]
    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)]
    #[cold]
    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::ControlCharacterWhileParsingString => {
                f.write_str("control character (\\u0000-\\u001F) found while parsing a string")
            }
            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 {
        write!(
            f,
            "Error({:?}, line: {}, column: {})",
            self.err.code.to_string(),
            self.err.line,
            self.err.column
        )
    }
}

impl de::Error for Error {
    #[cold]
    fn custom<T: Display>(msg: T) -> Error {
        make_error(msg.to_string())
    }

    #[cold]
    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 {
    #[cold]
    fn custom<T: Display>(msg: T) -> Error {
        make_error(msg.to_string())
    }
}

// Parse our own error message that looks like "{} at line {} column {}" to work
// around erased-serde round-tripping the error through de::Error::custom.
fn make_error(mut msg: String) -> Error {
    let (line, column) = parse_line_col(&mut msg).unwrap_or((0, 0));
    Error {
        err: Box::new(ErrorImpl {
            code: ErrorCode::Message(msg.into_boxed_str()),
            line: line,
            column: column,
        }),
    }
}

fn parse_line_col(msg: &mut String) -> Option<(usize, usize)> {
    let start_of_suffix = match msg.rfind(" at line ") {
        Some(index) => index,
        None => return None,
    };

    // Find start and end of line number.
    let start_of_line = start_of_suffix + " at line ".len();
    let mut end_of_line = start_of_line;
    while starts_with_digit(&msg[end_of_line..]) {
        end_of_line += 1;
    }

    if !msg[end_of_line..].starts_with(" column ") {
        return None;
    }

    // Find start and end of column number.
    let start_of_column = end_of_line + " column ".len();
    let mut end_of_column = start_of_column;
    while starts_with_digit(&msg[end_of_column..]) {
        end_of_column += 1;
    }

    if end_of_column < msg.len() {
        return None;
    }

    // Parse numbers.
    let line = match usize::from_str(&msg[start_of_line..end_of_line]) {
        Ok(line) => line,
        Err(_) => return None,
    };
    let column = match usize::from_str(&msg[start_of_column..end_of_column]) {
        Ok(column) => column,
        Err(_) => return None,
    };

    msg.truncate(start_of_suffix);
    Some((line, column))
}

fn starts_with_digit(slice: &str) -> bool {
    match slice.as_bytes().get(0) {
        None => false,
        Some(&byte) => byte >= b'0' && byte <= b'9',
    }
}
<commit_msg>Remove deprecated description() method from Error<commit_after>//! When serializing or deserializing JSON goes wrong.

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

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::ControlCharacterWhileParsingString
            | 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.
    ///
    /// ```edition2018
    /// 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),
            }
        }
    }
}

struct ErrorImpl {
    code: ErrorCode,
    line: usize,
    column: usize,
}

// Not public API. Should be pub(crate).
#[doc(hidden)]
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,

    /// Control character found while parsing a string.
    ControlCharacterWhileParsingString,

    /// 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)]
    #[cold]
    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).
    //
    // Update `eager_json` crate when this function changes.
    #[doc(hidden)]
    #[cold]
    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)]
    #[cold]
    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::ControlCharacterWhileParsingString => {
                f.write_str("control character (\\u0000-\\u001F) found while parsing a string")
            }
            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 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 {
        write!(
            f,
            "Error({:?}, line: {}, column: {})",
            self.err.code.to_string(),
            self.err.line,
            self.err.column
        )
    }
}

impl de::Error for Error {
    #[cold]
    fn custom<T: Display>(msg: T) -> Error {
        make_error(msg.to_string())
    }

    #[cold]
    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 {
    #[cold]
    fn custom<T: Display>(msg: T) -> Error {
        make_error(msg.to_string())
    }
}

// Parse our own error message that looks like "{} at line {} column {}" to work
// around erased-serde round-tripping the error through de::Error::custom.
fn make_error(mut msg: String) -> Error {
    let (line, column) = parse_line_col(&mut msg).unwrap_or((0, 0));
    Error {
        err: Box::new(ErrorImpl {
            code: ErrorCode::Message(msg.into_boxed_str()),
            line: line,
            column: column,
        }),
    }
}

fn parse_line_col(msg: &mut String) -> Option<(usize, usize)> {
    let start_of_suffix = match msg.rfind(" at line ") {
        Some(index) => index,
        None => return None,
    };

    // Find start and end of line number.
    let start_of_line = start_of_suffix + " at line ".len();
    let mut end_of_line = start_of_line;
    while starts_with_digit(&msg[end_of_line..]) {
        end_of_line += 1;
    }

    if !msg[end_of_line..].starts_with(" column ") {
        return None;
    }

    // Find start and end of column number.
    let start_of_column = end_of_line + " column ".len();
    let mut end_of_column = start_of_column;
    while starts_with_digit(&msg[end_of_column..]) {
        end_of_column += 1;
    }

    if end_of_column < msg.len() {
        return None;
    }

    // Parse numbers.
    let line = match usize::from_str(&msg[start_of_line..end_of_line]) {
        Ok(line) => line,
        Err(_) => return None,
    };
    let column = match usize::from_str(&msg[start_of_column..end_of_column]) {
        Ok(column) => column,
        Err(_) => return None,
    };

    msg.truncate(start_of_suffix);
    Some((line, column))
}

fn starts_with_digit(slice: &str) -> bool {
    match slice.as_bytes().get(0) {
        None => false,
        Some(&byte) => byte >= b'0' && byte <= b'9',
    }
}
<|endoftext|>