1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use std::fmt::Debug;

use crate::ctx::Ctx;
use crate::map::ErasedTy;
use crate::opt::Action;
use crate::trace_log;
use crate::Error;
use crate::RawVal;

use super::AnyValue;
use super::RawValParser;
use super::ValValidator;

#[cfg(feature = "sync")]
pub type StoreHandler<T> =
    Box<dyn FnMut(Option<&RawVal>, &Ctx, &Action, &mut T) -> Result<(), Error> + Send + Sync>;

#[cfg(not(feature = "sync"))]
pub type StoreHandler<T> =
    Box<dyn FnMut(Option<&RawVal>, &Ctx, &Action, &mut T) -> Result<(), Error>>;

/// [`ValStorer`] perform the value storing action.
pub struct ValStorer(StoreHandler<AnyValue>);

impl Debug for ValStorer {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("WriterHandler").field(&"{...}").finish()
    }
}

impl ValStorer {
    pub fn new(handler: StoreHandler<AnyValue>) -> Self {
        Self(handler)
    }

    pub fn fallback<U: ErasedTy + RawValParser>() -> Self {
        Self(Self::fallback_handler::<U>())
    }

    /// Create a [`ValStorer`] with a value validator.
    /// The [`invoke`](ValStorer::invoke) will return a [`failure`](Error::is_failure)
    /// if value check failed.
    pub fn new_validator<U: ErasedTy + RawValParser>(validator: ValValidator<U>) -> Self {
        Self(Self::validator(validator))
    }

    /// Invoke the inner value store handler on [`AnyValue`].
    pub fn invoke(
        &mut self,
        raw: Option<&RawVal>,
        ctx: &Ctx,
        act: &Action,
        arg: &mut AnyValue,
    ) -> Result<(), Error> {
        crate::trace_log!("Saving raw value({:?}) for {}", raw, ctx.uid()?);
        (self.0)(raw, ctx, act, arg)
    }

    pub fn validator<U: ErasedTy + RawValParser>(
        validator: ValValidator<U>,
    ) -> StoreHandler<AnyValue> {
        Box::new(
            move |raw: Option<&RawVal>, ctx: &Ctx, act: &Action, handler: &mut AnyValue| {
                let val = U::parse(raw, ctx).map_err(Into::into)?;

                if !validator.invoke(&val) {
                    let uid = ctx.uid()?;

                    trace_log!(
                        "Validator value storer failed, parsing {:?} -> {:?}",
                        raw,
                        val
                    );
                    Err(crate::raise_failure!(
                        "Option value check failed: `{:?}`",
                        ctx.inner_ctx().ok(),
                    )
                    .with_uid(uid))
                } else {
                    trace_log!(
                        "Validator value storer okay, parsing {:?} -> {:?}",
                        raw,
                        val
                    );
                    act.store1(Some(val), handler);
                    Ok(())
                }
            },
        )
    }

    pub fn fallback_handler<U: ErasedTy + RawValParser>() -> StoreHandler<AnyValue> {
        Box::new(
            |raw: Option<&RawVal>, ctx: &Ctx, act: &Action, handler: &mut AnyValue| {
                let val = U::parse(raw, ctx).map_err(Into::into);

                trace_log!("Fallback value storer, parsing {:?} -> {:?}", raw, val);
                act.store1(Some(val?), handler);
                Ok(())
            },
        )
    }
}

impl<U: ErasedTy + RawValParser> From<ValValidator<U>> for ValStorer {
    fn from(validator: ValValidator<U>) -> Self {
        Self::new_validator(validator)
    }
}

impl<U: ErasedTy + RawValParser> From<Option<ValValidator<U>>> for ValStorer {
    fn from(validator: Option<ValValidator<U>>) -> Self {
        if let Some(validator) = validator {
            Self::new_validator(validator)
        } else {
            Self::fallback::<U>()
        }
    }
}