problem_details_mapper/mappers/
problemdetails_mapper.rs

1use 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}