/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #[cfg(feature = "serialize")] use serde::ser::{Serialize, SerializeStruct, Serializer}; use std::error; use std::error::Error; use std::fmt; extern crate url; use address::AddressType; use std::num::ParseFloatError; use std::num::ParseIntError; #[derive(Debug, Clone)] pub enum SdpParserInternalError { UnknownAddressType(String), AddressTypeMismatch { found: AddressType, expected: AddressType, }, Generic(String), Unsupported(String), Integer(ParseIntError), Float(ParseFloatError), Domain(url::ParseError), IpAddress(std::net::AddrParseError), } const INTERNAL_ERROR_MESSAGE_UNKNOWN_ADDRESS_TYPE: &str = "Unknown address type"; const INTERNAL_ERROR_MESSAGE_ADDRESS_TYPE_MISMATCH: &str = "Address is of a different type(1) than declared(2)"; impl fmt::Display for SdpParserInternalError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { SdpParserInternalError::UnknownAddressType(ref unknown) => write!( f, "{}: {}", INTERNAL_ERROR_MESSAGE_UNKNOWN_ADDRESS_TYPE, unknown ), SdpParserInternalError::AddressTypeMismatch { found, expected } => write!( f, "{}: {}, {}", INTERNAL_ERROR_MESSAGE_ADDRESS_TYPE_MISMATCH, found, expected ), SdpParserInternalError::Generic(ref message) => write!(f, "Parsing error: {}", message), SdpParserInternalError::Unsupported(ref message) => { write!(f, "Unsupported parsing error: {}", message) } SdpParserInternalError::Integer(ref error) => { write!(f, "Integer parsing error: {}", error) } SdpParserInternalError::Float(ref error) => write!(f, "Float parsing error: {}", error), SdpParserInternalError::Domain(ref error) => { write!(f, "Domain name parsing error: {}", error) } SdpParserInternalError::IpAddress(ref error) => { write!(f, "IP address parsing error: {}", error) } } } } impl Error for SdpParserInternalError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { SdpParserInternalError::Integer(ref error) => Some(error), SdpParserInternalError::Float(ref error) => Some(error), SdpParserInternalError::Domain(ref error) => Some(error), SdpParserInternalError::IpAddress(ref error) => Some(error), // Can't tell much more about our internal errors _ => None, } } } #[derive(Debug, Clone)] 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(&self, serializer: S) -> Result 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, line_number, line ), SdpParserError::Unsupported { ref error, ref line, ref line_number, } => write!( f, "Unsupported: {} in line({}): {}", error, line_number, line ), SdpParserError::Sequence { ref message, ref line_number, } => write!(f, "Sequence error in line({}): {}", line_number, message), } } } impl Error for SdpParserError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { SdpParserError::Line { ref error, .. } | SdpParserError::Unsupported { ref error, .. } => Some(error), // Can't tell much more about our internal errors _ => None, } } } impl From for SdpParserInternalError { fn from(err: ParseIntError) -> SdpParserInternalError { SdpParserInternalError::Integer(err) } } impl From for SdpParserInternalError { fn from(err: url::ParseError) -> SdpParserInternalError { SdpParserInternalError::Domain(err) } } impl From for SdpParserInternalError { fn from(err: std::net::AddrParseError) -> SdpParserInternalError { SdpParserInternalError::IpAddress(err) } } impl From for SdpParserInternalError { fn from(err: ParseFloatError) -> SdpParserInternalError { SdpParserInternalError::Float(err) } } #[cfg(test)] mod tests { use super::*; use address::Address; use std::str::FromStr; #[test] fn test_sdp_parser_internal_error_unknown_address_type() { let error = SdpParserInternalError::UnknownAddressType("foo".to_string()); assert_eq!( format!("{}", error), format!("{}: {}", INTERNAL_ERROR_MESSAGE_UNKNOWN_ADDRESS_TYPE, "foo") ); assert!(error.source().is_none()); } #[test] fn test_sdp_parser_internal_error_address_type_mismatch() { let error = SdpParserInternalError::AddressTypeMismatch { found: AddressType::IpV4, expected: AddressType::IpV6, }; assert_eq!( format!("{}", error), format!( "{}: {}, {}", INTERNAL_ERROR_MESSAGE_ADDRESS_TYPE_MISMATCH, AddressType::IpV4, AddressType::IpV6 ) ); assert!(error.source().is_none()); } #[test] fn test_sdp_parser_internal_error_generic() { let generic = SdpParserInternalError::Generic("generic message".to_string()); assert_eq!(format!("{}", generic), "Parsing error: generic message"); assert!(generic.source().is_none()); } #[test] 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!(unsupported.source().is_none()); } #[test] fn test_sdp_parser_internal_error_integer() { let v = "12a"; let integer = v.parse::(); 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!(!int_err.source().is_none()); } #[test] fn test_sdp_parser_internal_error_float() { let v = "12.2a"; let float = v.parse::(); assert!(float.is_err()); let int_err = SdpParserInternalError::Float(float.err().unwrap()); assert_eq!( format!("{}", int_err), "Float parsing error: invalid float literal" ); assert!(!int_err.source().is_none()); } #[test] fn test_sdp_parser_internal_error_address() { let v = "127.0.0.500"; let addr_err = Address::from_str(v).err().unwrap(); assert_eq!( format!("{}", addr_err), "Domain name parsing error: invalid IPv4 address" ); assert!(!addr_err.source().is_none()); } #[test] 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: Parsing error: test message in line(13): test line" ); assert!(line1.source().is_some()); } #[test] 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: Parsing error: unsupported value in line(21): unsupported line" ); assert!(unsupported1.source().is_some()); } #[test] 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!(sequence1.source().is_none()); } }