problem_details_mapper/mappers/
problemdetails_mapper.rs1use std::{error::Error, sync::RwLock};
2use problem_details::ProblemDetails;
3use crate::{traits::into_problemdetails::IntoProblemDetails, errors::mapper_error::MapperError};
4
5type MapFn = &'static (dyn Fn(&Box<dyn Error>) -> Option<ProblemDetails> + Sync);
6
7static MAPS: RwLock<Vec<MapFn>> = RwLock::new(Vec::new());
8
9pub struct ProblemDetailsMapper;
10
11impl ProblemDetailsMapper {
12 pub fn map(error: Box<dyn Error>) -> Option<ProblemDetails> {
13 let mut details: Option<ProblemDetails> = None;
14
15 if let Ok(maps) = MAPS.read() {
16 for map in maps.iter() {
17 details = details.or_else(|| map(&error));
18 }
19 }
20
21 details
22 }
23
24 pub fn setup<F>(setup: F) -> Result<(), MapperError>
25 where F: Fn(&mut ProblemDetailsOptions) {
26 let mut maps = MAPS.write().map_err(|e| MapperError::new("error getting write lock", Some(Box::new(e))))?;
27 let mut options = ProblemDetailsOptions::new();
28 setup(&mut options);
29 *maps = options.maps;
30 Ok(())
31 }
32}
33
34pub struct ProblemDetailsOptions {
35 maps: Vec<MapFn>
36}
37
38impl ProblemDetailsOptions {
39 pub fn new() -> Self {
40 Self {
41 maps: Vec::new()
42 }
43 }
44
45 pub fn map<TType>(&mut self)
46 where TType : Error + IntoProblemDetails + 'static {
47 self.maps.push(&Self::map_type::<TType>)
48 }
49
50 pub fn map_std_err(&mut self) {
51 self.maps.push(&Self::map_default_error)
52 }
53
54 fn map_type<TType>(error: &Box<dyn Error>) -> Option<ProblemDetails>
55 where TType : Error + IntoProblemDetails + 'static {
56 let concrete_error = error.as_ref().downcast_ref::<TType>()?;
57 Some(concrete_error.into_problemdetails())
58 }
59
60 fn map_default_error(error: &Box<dyn Error>) -> Option<ProblemDetails> {
61 use crate::builders::problemdetails_builder::ProblemDetailsBuilder;
62 const TYPE: &'static str = "https://errors.io/unkownerror";
63 Some(ProblemDetailsBuilder::build_server_error(
64 Some(format!("{}", error)),
65 Some(TYPE)))
66 }
67}