#![allow(warnings)] use std::io; use std::convert::Infallible; use std::net::{AddrParseError, IpAddr}; use std::num::TryFromIntError; extern crate derive_constructors_proc; pub use derive_constructors_proc::*; // Creates a constructor function named 'with_age_and_name' with parameters (age: u8, // name: &'static str), the other fields are initialized as {id: "Jorge", family_names: Vec("Rico", // "Vivas"), appeared_in_movies: 0}, notice 'appeared_in_movies' get's value 0 since u32::default() // is 0 #[constructor( named(with_age_and_name), pattern(From), fields(age, name), defaults( id("Jorge".to_string()), family_names(vec ! ["Rico", "Vivas"]) ) )] // Similar to previous constructor, but it uses TryFrom pattern instead of From, this mean the // parameters now are (age: TryAge, name: TryName) where TryAge and TryFrom are types // implemententing TryFrom -> u8/&'static str, in other words, types that can turn into u8 // (the type of age) and into &'static str (the type of name). // // Note 1: the result is Result, where EnumError is an enum indicating // which value failed and it's error, for example, if introduced age as 500 (A value from which u8 // cannot result), the error would be: EnumError(AgeError(TryFromIntError())). // // Note 2: #[constructor( named(try_with_age_and_name), pattern(TryFrom), fields(age, name), defaults( id("Jorge".to_string()), family_names(vec ! ["Rico", "Vivas"]) ), error_enum_metadata(# [derive(Debug, PartialEq)]), error_enum_named(GetWithAgeAndNameError), )] #[derive(From, Debug, PartialEq)] pub struct CharacterInfo { age: u8, name: &'static str, #[no_from("Jorge".to_string())] id: String, #[no_from(vec ! ["Rico", "Vivas"])] family_names: Vec<&'static str>, #[no_from] appeared_in_movies: u8, } #[derive(From, Debug)] pub enum MyError { IO(std::io::Error), #[no_from] CustomIOError(io::Error), MyTwoIo { io_err: io::Error, other_io_err: io::Error }, } #[derive(Debug, From)] enum MyNumErrors { IO(std::io::Error), Infallible(Infallible), TryFromIntError(TryFromIntError), } pub trait FlattenError { fn flatten_err(self) -> Result where Error: From + From; fn flatten_err_ext(self) -> Result where InternalError: Into; fn flatten_err_int(self) -> Result where ExternalError: Into; } impl FlattenError for Result, ExternalError> { fn flatten_err(self) -> Result where ResError: From + From { match self { Err(external_error) => Result::Err(external_error.into()), Ok(internal_result) => { match internal_result { Err(internal_error) => Result::Err(internal_error.into()), Ok(value) => Result::Ok(value), } } } } fn flatten_err_ext(self) -> Result where InternalError: Into { match self { Err(external_error) => Result::Err(external_error), Ok(internal_result) => { match internal_result { Err(internal_error) => Result::Err(internal_error.into()), Ok(value) => Result::Ok(value), } } } } fn flatten_err_int(self) -> Result where ExternalError: Into { match self { Err(external_error) => Result::Err(external_error.into()), Ok(internal_result) => { match internal_result { Err(internal_error) => Result::Err(internal_error), Ok(value) => Result::Ok(value), } } } } } #[test] fn test() { assert_eq!( CharacterInfo::from((23, "Jorge")), CharacterInfo { age: 23, name: "Jorge", id: "Jorge".to_string(), family_names: vec!["Rico", "Vivas"], appeared_in_movies: 0 } ); assert_eq!( CharacterInfo::try_with_age_and_name(2003, "Jorge"), Err(GetWithAgeAndNameError::AgeError(u8::try_from(2003).unwrap_err())) ); let error = std::fs::read_to_string("").map(|_| std::fs::read_to_string("").map(|_| std::fs::read_to_string(""))) .flatten_err::().flatten_err_ext(); let is_io_error = match error.unwrap_err() { MyNumErrors::IO(_) => true, _ => false, }; assert!(is_io_error); let my_two_errors_is_two_errors = match MyError::from(( std::fs::read_to_string("").expect_err(""), std::fs::read_to_string("").expect_err("") )) { MyError::MyTwoIo { .. } => true, _ => false, }; assert!(my_two_errors_is_two_errors); }