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
120
121
122
123
124
125
126
127
128
129
130
131
use std::any;
use std::any::type_name;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;

use crate::{
    get_debug_fmt_fn, get_display_fmt_fn, AnyValue, DebugFmtFn, DisplayFmtFn, Fmt, Phlow,
    PhlowObject, PhlowView,
};

#[derive(Clone)]
#[repr(C)]
pub struct PhlowExtension {
    view_methods_fn: Arc<dyn Fn(&PhlowExtension) -> Vec<PhlowViewMethod> + Send + Sync + 'static>,
    category: &'static str,
    target: &'static str,
}

impl PhlowExtension {
    pub fn new<Category, T: Phlow<Category> + 'static>() -> Self {
        Self {
            view_methods_fn: Arc::new(|extension| T::phlow_view_methods(extension)),
            category: any::type_name::<Category>(),
            target: any::type_name::<T>(),
        }
    }

    pub fn category_name(&self) -> &str {
        self.category
    }

    pub fn target_type_name(&self) -> &str {
        self.target
    }

    pub fn view_methods(&self) -> Vec<PhlowViewMethod> {
        (self.view_methods_fn)(self)
    }
}

impl Debug for PhlowExtension {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct(any::type_name::<Self>())
            .field("category", &self.category)
            .field("target", &self.target)
            .finish()
    }
}

#[derive(Clone)]
#[repr(C)]
pub struct PhlowViewMethod {
    pub method: Arc<dyn Fn(&PhlowObject, &PhlowViewMethod) -> Option<Box<dyn PhlowView>>>,
    pub extension: PhlowExtension,
    pub method_name: String,
    pub full_method_name: String,
    pub source_code: String,
}

impl PhlowViewMethod {
    pub fn as_view(&self, object: &PhlowObject) -> Option<Box<dyn PhlowView>> {
        (self.method)(object, self)
    }

    pub fn source_code(&self) -> &str {
        self.source_code.as_str()
    }
}

impl Debug for PhlowViewMethod {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.full_method_name.as_str())
    }
}

#[derive(Clone)]
#[repr(C)]
pub struct PrintExtensions {
    display_fmt_fn: Option<DisplayFmtFn>,
    debug_fmt_fn: Option<DebugFmtFn>,
}

impl PrintExtensions {
    pub fn new<T: 'static>() -> Self {
        Self {
            display_fmt_fn: get_display_fmt_fn::<T>(),
            debug_fmt_fn: get_debug_fmt_fn::<T>(),
        }
    }

    pub fn to_string(&self, value: &AnyValue) -> String {
        self.display_string(value)
            .or_else(|| self.debug_string(value))
            .unwrap_or_else(|| "Doesn't support Display or Debug".to_string())
    }

    pub fn debug_string(&self, value: &AnyValue) -> Option<String> {
        self.debug_fmt_fn
            .as_ref()
            .map(|func| format!("{:?}", &Fmt(|f| func(value, f))))
    }

    pub fn display_string(&self, value: &AnyValue) -> Option<String> {
        self.display_fmt_fn
            .as_ref()
            .map(|func| format!("{}", &Fmt(|f| func(value, f))))
    }
}

impl Debug for PrintExtensions {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct(type_name::<Self>())
            .field(
                "display_fmt_fn",
                if self.display_fmt_fn.is_some() {
                    &"Some(...)"
                } else {
                    &"None"
                },
            )
            .field(
                "debug_fmt_fn",
                if self.debug_fmt_fn.is_some() {
                    &"Some(...)"
                } else {
                    &"None"
                },
            )
            .finish()
    }
}